home *** CD-ROM | disk | FTP | other *** search
/ Aminet 37 / Aminet 37 (2000)(Schatztruhe)[!][Jun 2000].iso / Aminet / comm / bbs / cit_src_AD08.lha / cit_zmodem.c < prev    next >
C/C++ Source or Header  |  1997-08-21  |  106KB  |  4,018 lines

  1. #include <exec/types.h>
  2. #include <dos/dos.h>
  3. #include <devices/timer.h>
  4. #include <exec/memory.h>
  5. #include <ctype.h>
  6. #include <time.h>
  7. #include <stdio.h>
  8. #include <stdlib.h>
  9. #include <string.h>
  10. #include <exec/execbase.h>
  11. #include <math.h>
  12. #include <devices/timer.h>
  13. #include <devices/serial.h>
  14. #include "xproto.h"
  15. #include <exec/memory.h>
  16. #include "ctdl.h"
  17. #include "sysdep.h"
  18. #include "xproto.h"
  19. #include "zmodem.h"
  20. #include "xprzmodem.h"
  21.  
  22. struct Library *TimerBase;
  23. static struct XPR_IO xio;
  24. static struct timerequest treq;
  25. static struct MsgPort *tport;
  26. static char timeropen;
  27.  
  28. extern CONFIG    cfg;            /* Lots an lots of variables    */
  29.  
  30. extern struct IOExtSer *mySerReadMsg;
  31. extern struct MsgPort *mySerReadPort;
  32. struct IOExtSer *xpr_serio;
  33. struct MsgPort *smp;
  34.  
  35. long xpr_sread(char *buffer, long size, long timeout);
  36. long xpr_swrite(char *buffer, long size);
  37. long xpr_sflush(void);
  38. long xpr_ffirst(char *buffer, char *pattern);
  39. long xpr_fnext(long OldState, char *buffer, char *pattern);
  40. long xpr_finfo(char *name, long type);
  41. long xpr_gets(char *b, char *p);
  42.  
  43.  
  44. long xpr_chkabort(void);
  45. void init_xpr ( struct XPR_IO *IO );
  46. void plog(char *string, long arg1, long arg2  );
  47.  
  48.  
  49. long   display_update (struct XPR_UPDATE *xu );
  50. long   Do_Zmodem(char *filename, int sending);
  51.  
  52. void close_xpr ( void );
  53.  
  54. char *filelist;   /* initial file list from Citadel */
  55.  
  56. long
  57. Do_Zmodem(filename, sending)
  58. char   *filename;            /* file(s) to  send/recieve  */
  59. int     sending;             /* TRUE - sending, FALSE - receive */
  60.   {
  61.   long status;
  62.   plog("Files:%s Direction:%s",(long)filename, (long)(sending ? "TRUE" : "FALSE") );
  63.   xpr_serio = mySerReadMsg;
  64.   smp       = mySerReadPort;
  65.   init_xpr(&xio);
  66.   status = TRUE;
  67.   if (!xpr_chkabort())
  68.     {
  69.     filelist         = filename;
  70.     xio.xpr_filename = strtok(filelist," ");  /* Citadel delimits with a space*/
  71.     if (!sending)
  72.       {
  73.       status = XProtocolSend(&xio);
  74.       plog("XProtocolSend returned: %08.8lX",status,0L);
  75.       }
  76.     else
  77.       {
  78.       status = XProtocolReceive(&xio);
  79.       plog("XProtocolReceive returned: %08.8lX",status,0L);
  80.       };
  81.     };
  82.   XProtocolCleanup(&xio);
  83.   return  status;
  84.   }
  85. void
  86. init_xpr(struct XPR_IO *IO)
  87.   {
  88.   plog("init_xpr: XPR_IO =%08.8lX", (long)IO, 0L);
  89.   IO->xpr_filename  = NULL;
  90.   IO->xpr_data      = NULL;
  91.   }
  92.  
  93. void
  94. plog(char *string, long arg1, long arg2)
  95.   {
  96.   long    t;
  97.     t = time(0);
  98.     splitF(NULL,"%24.24s : ", ctime(&t));
  99.     splitF(NULL, string, arg1, arg2);
  100.     splitF(NULL, "\n", 1);
  101.  
  102.   }
  103.  
  104. char the_protocol[20];  /* the current protocol name */
  105. char the_file[30];      /* the current filename */
  106. long the_size;          /* size of current file */
  107.  
  108. long   display_update (struct XPR_UPDATE *xu )
  109.   {
  110.   int flag = FALSE;
  111.   if( !xu)
  112.     {
  113.     plog(" XPR_UPDATE is NULL",0L, 0L);
  114.     return 0;
  115.     }
  116.   if( XPRU_PROTOCOL && xu->xpru_updatemask)
  117.     {
  118.     if( xu->xpru_protocol)strncpy(the_protocol,xu->xpru_protocol,19);
  119.     the_protocol[19] = '\0';
  120.     };
  121.   if( XPRU_FILENAME && xu->xpru_updatemask)
  122.     {
  123.     if( xu->xpru_filename)strncpy(the_file,xu->xpru_filename,29);
  124.     the_protocol[19] = '\0';
  125.     flag = TRUE;
  126.     };
  127.   if( XPRU_FILESIZE && xu->xpru_updatemask)the_size = xu->xpru_filesize;
  128.   if( XPRU_MSG && xu->xpru_updatemask)
  129.     plog("XPRU_MSG:%s",(long)xu->xpru_msg,0L);
  130.   if( XPRU_ERRORMSG && xu->xpru_updatemask)
  131.     plog("XPRU_ERRORMSG:%s on file %s",(long)xu->xpru_errormsg,(long)the_file);
  132.   if( XPRU_ERRORS && xu->xpru_updatemask)
  133.     {
  134.     if( xu->xpru_errors != 0 )
  135.       plog("XPRU_ERRORS:%ld on file %s",(long)xu->xpru_errors,(long)the_file);
  136.     };
  137.   if( flag )
  138.     {
  139.     plog("Protocol:%s File:%s",(long)the_protocol,(long)the_file);
  140.     };
  141.   return 1;
  142.   }
  143.  
  144. long    xpr_chkabort(void)
  145.   {
  146.   return (gotCarrier()? 0L : -1L);
  147.  
  148.   }
  149. long  opentimer(void)
  150.   {
  151.   plog("opentimer", 0L, 0L);
  152.   tport = CreatePort(0, 0);
  153.   if (!tport)  return (-1);
  154.   treq.tr_node.io_Message.mn_ReplyPort = tport;
  155.   if (OpenDevice("timer.device", UNIT_VBLANK, (struct IORequest *) &treq, 0))
  156.   return (-1);
  157.   TimerBase = (struct Library *)treq.tr_node.io_Device;
  158.   timeropen = 1;
  159.   return (0);
  160.  
  161.   }
  162. void  closetimer(void)
  163.   {
  164.   plog("closetimer", 0L, 0L);
  165.   if (timeropen)
  166.   CloseDevice((struct IORequest *) &treq);
  167.   if (tport)
  168.   DeletePort(tport);
  169.   TimerBase = NULL;
  170.   }
  171. void  qtimer(long micros)
  172.   {
  173.   long    secs = 0;
  174.   plog("qtimer: micros = %ld", micros, 0L);
  175.   if (micros > 1000000)
  176.     {
  177.     secs = micros / 1000000;
  178.     micros = micros % 1000000;
  179.  
  180.     }
  181.   treq.tr_time.tv_micro = micros;
  182.   treq.tr_time.tv_secs = secs;
  183.   treq.tr_node.io_Command = TR_ADDREQUEST;
  184.   /* printf("QTIMER  * s=%ld  * m=%ld\n",secs,micros); */
  185.   SendIO((struct IORequest *) &treq);
  186.  
  187.   }
  188. /* the * finfo-function  */
  189. long
  190. xpr_finfo(char * FileName,LONG InfoType)
  191.   {
  192.   struct FileInfoBlock    *FileInfo;
  193.   LONG                     Size=0;
  194.   plog("finfo:%s, InfoType:%ld", 0L, 0L);
  195.   switch(InfoType)
  196.     {
  197.     case 1:       /* Return the file size. */
  198.       if(FileInfo = (struct FileInfoBlock *)AllocMem(sizeof(struct FileInfoBlock), MEMF_CLEAR))
  199.         {
  200.         BPTR    FileLock;
  201.         if(FileLock = Lock(FileName,ACCESS_READ))
  202.           {
  203.           if(Examine(FileLock,FileInfo))
  204.             {
  205.             if(FileInfo -> fib_DirEntryType < 0)Size = FileInfo->fib_Size;
  206.             };
  207.           UnLock(FileLock);
  208.           };
  209.         FreeMem(FileInfo, sizeof(struct FileInfoBlock));
  210.         };
  211.       break;
  212.     case 2:         /* Return the file transfer mode. */
  213.       Size = 1; /* always return Binary */
  214.     break;
  215.    }
  216. return Size;
  217. }
  218.  
  219.  
  220. /* the * serwrite  * function  */
  221. long
  222. xpr_swrite(char *buffer, long size)
  223.   {
  224.   plog("swrite:%08.8lX of size %ld", (long)buffer, size);
  225.   xpr_serio->IOSer.io_Length  = size;
  226.   xpr_serio->IOSer.io_Data    = buffer;
  227.   xpr_serio->IOSer.io_Command = CMD_WRITE;
  228.   DoIO((struct IORequest *) xpr_serio);
  229.   if( xpr_serio->IOSer.io_Error )
  230.     plog("  Error:%08.8lx", xpr_serio->IOSer.io_Error, 0L);
  231.   return ((long) xpr_serio->IOSer.io_Error);
  232.  
  233.   }
  234. /* the * serread  * function  */
  235. long
  236. xpr_sread(char *buffer, long size, long timeout)
  237.   {
  238.   long    flag = 1 << xpr_serio->IOSer.io_Message.mn_ReplyPort->mp_SigBit;
  239.   long    len,
  240.   nflag;
  241.   plog("sread: size %ld with timeout of %ld", size, timeout);
  242.   SetSignal(0, flag);
  243.   if (timeout)
  244.     {
  245.     flag |= 1 << tport->mp_SigBit;
  246.     /* printf("Starting  * timer...\n"); */
  247.     qtimer(timeout);
  248.  
  249.     }
  250.   else
  251.     {
  252.     xpr_serio->IOSer.io_Command = SDCMD_QUERY;
  253.     DoIO((struct IORequest *) xpr_serio);
  254.     if (!(len = xpr_serio->IOSer.io_Actual))
  255.     return (0);
  256.     else
  257.       {
  258.       if (len > size)
  259.       len = size;
  260.       xpr_serio->IOSer.io_Command = CMD_READ;
  261.       xpr_serio->IOSer.io_Data = buffer;
  262.       xpr_serio->IOSer.io_Length = len;
  263.       DoIO((struct IORequest *) xpr_serio);
  264.       /* printf("Fastread  * return  * * * *
  265.       * %ld\n",xpr_serio->IOSer.io_Actual); */
  266.       return ((long) xpr_serio->IOSer.io_Actual);
  267.  
  268.       }
  269.  
  270.     }
  271.   SetSignal(0, flag);
  272.   xpr_serio->IOSer.io_Command = CMD_READ;
  273.   xpr_serio->IOSer.io_Data = buffer;
  274.   xpr_serio->IOSer.io_Length = size;
  275.   SendIO((struct IORequest *) xpr_serio);
  276.   nflag = Wait(flag);
  277.   if (nflag)
  278.     {
  279.     AbortIO((struct IORequest *) &treq);
  280.     AbortIO((struct IORequest *) xpr_serio);
  281.     WaitIO((struct IORequest *) &treq);
  282.     WaitIO((struct IORequest *) xpr_serio);
  283.     return (-1);
  284.  
  285.     }
  286.   if (nflag & (1 << xpr_serio->IOSer.io_Message.mn_ReplyPort->mp_SigBit))
  287.     {
  288.     AbortIO((struct IORequest *) &treq);
  289.     WaitIO((struct IORequest *) xpr_serio);
  290.     WaitIO((struct IORequest *) &treq);
  291.     return ((long) xpr_serio->IOSer.io_Actual);
  292.  
  293.     }
  294.   plog("  Timeout occured", 0L, 0L);
  295.   AbortIO((struct IORequest *) xpr_serio);
  296.   WaitIO((struct IORequest *) &treq);
  297.   WaitIO((struct IORequest *) xpr_serio);
  298.   return ((long) xpr_serio->IOSer.io_Actual);
  299.  
  300.   }
  301. /* sflush  * - * flushes  * serial  * port  */
  302. long
  303. xpr_sflush(void)
  304.   {
  305.   plog("sflush", 0L, 0L);
  306.   xpr_serio->IOSer.io_Command = CMD_CLEAR;
  307.   DoIO((struct IORequest *) xpr_serio);
  308.   if( xpr_serio->IOSer.io_Error )
  309.     plog("  Error:%08.8lx", xpr_serio->IOSer.io_Error, 0L);
  310.   return ((long) xpr_serio->IOSer.io_Error);
  311.  
  312.   }
  313. /**
  314.   ffirst() -- setup first filename and return it
  315. **/
  316. long
  317. xpr_ffirst(char *buffer, char *pattern)
  318.   {
  319.   char *token;
  320.   plog("ffirst",0L,0L);
  321.   token = strtok(NULL," ");  /* Citadel delimits filenames with a space*/
  322.   if( token != NULL )
  323.     {
  324.     plog("  filename:%s", (long)token, 0L);
  325.     strcpy(buffer,token);
  326.     return(1);
  327.     }
  328.   return (0);
  329.   }
  330.  
  331. long
  332. xpr_fnext(long OldState,
  333.           char *buffer,
  334.           char *pattern)
  335.   {
  336.   char *token;
  337.   plog("fnext",0L,0L);
  338.   token = strtok(NULL," ");  /* Citadel delimits filenames with a space*/
  339.   if( token != NULL )
  340.     {
  341.     plog("  filename:%s", (long)token, 0L);
  342.     strcpy(buffer,token);
  343.     return(1);
  344.     }
  345.   return (0);
  346.   }
  347.  
  348.  
  349. void
  350. close_xpr(void)
  351.   {
  352.   plog("close_xpr",0L, 0L);
  353.   closetimer();
  354.  
  355.   }
  356. /**********************************************************************
  357.  *   Z M . C
  358.  *    ZMODEM protocol primitives
  359.  *    01-19-87  Chuck Forsberg Omen Technology Inc
  360.  *
  361.  * 05-Apr-95: Converted to become a part of Citadel
  362.  *
  363.  * 29 July 89:
  364.  * Major overhaul by Rick Huebner for adaptation to Amiga XPR protocol spec
  365.  *
  366.  * 28 October 89:
  367.  * Converted to Lattice C 5.04
  368.  *
  369.  * 15 November 1991
  370.  * Code added to support CRC-32 by William M. Perkins.
  371.  *
  372.  * 28 June 1993
  373.  * Added run-length encoding code from original ZModem sources.
  374.  **********************************************************************/
  375.  
  376. /*
  377.  * Fast table-driven CRC functions for ZMODEM
  378.  * * extracted from RBSB.C by Chuck Forsberg, Omen Technology, Inc.
  379.  * *
  380.  * * crctab calculated by Mark G. Mendel, Network Systems Corporation
  381.  */
  382.  
  383. static unsigned short crctab[256] =
  384. {
  385.   0x0000, 0x1021, 0x2042, 0x3063, 0x4084, 0x50a5, 0x60c6, 0x70e7,
  386.   0x8108, 0x9129, 0xa14a, 0xb16b, 0xc18c, 0xd1ad, 0xe1ce, 0xf1ef,
  387.   0x1231, 0x0210, 0x3273, 0x2252, 0x52b5, 0x4294, 0x72f7, 0x62d6,
  388.   0x9339, 0x8318, 0xb37b, 0xa35a, 0xd3bd, 0xc39c, 0xf3ff, 0xe3de,
  389.   0x2462, 0x3443, 0x0420, 0x1401, 0x64e6, 0x74c7, 0x44a4, 0x5485,
  390.   0xa56a, 0xb54b, 0x8528, 0x9509, 0xe5ee, 0xf5cf, 0xc5ac, 0xd58d,
  391.   0x3653, 0x2672, 0x1611, 0x0630, 0x76d7, 0x66f6, 0x5695, 0x46b4,
  392.   0xb75b, 0xa77a, 0x9719, 0x8738, 0xf7df, 0xe7fe, 0xd79d, 0xc7bc,
  393.   0x48c4, 0x58e5, 0x6886, 0x78a7, 0x0840, 0x1861, 0x2802, 0x3823,
  394.   0xc9cc, 0xd9ed, 0xe98e, 0xf9af, 0x8948, 0x9969, 0xa90a, 0xb92b,
  395.   0x5af5, 0x4ad4, 0x7ab7, 0x6a96, 0x1a71, 0x0a50, 0x3a33, 0x2a12,
  396.   0xdbfd, 0xcbdc, 0xfbbf, 0xeb9e, 0x9b79, 0x8b58, 0xbb3b, 0xab1a,
  397.   0x6ca6, 0x7c87, 0x4ce4, 0x5cc5, 0x2c22, 0x3c03, 0x0c60, 0x1c41,
  398.   0xedae, 0xfd8f, 0xcdec, 0xddcd, 0xad2a, 0xbd0b, 0x8d68, 0x9d49,
  399.   0x7e97, 0x6eb6, 0x5ed5, 0x4ef4, 0x3e13, 0x2e32, 0x1e51, 0x0e70,
  400.   0xff9f, 0xefbe, 0xdfdd, 0xcffc, 0xbf1b, 0xaf3a, 0x9f59, 0x8f78,
  401.   0x9188, 0x81a9, 0xb1ca, 0xa1eb, 0xd10c, 0xc12d, 0xf14e, 0xe16f,
  402.   0x1080, 0x00a1, 0x30c2, 0x20e3, 0x5004, 0x4025, 0x7046, 0x6067,
  403.   0x83b9, 0x9398, 0xa3fb, 0xb3da, 0xc33d, 0xd31c, 0xe37f, 0xf35e,
  404.   0x02b1, 0x1290, 0x22f3, 0x32d2, 0x4235, 0x5214, 0x6277, 0x7256,
  405.   0xb5ea, 0xa5cb, 0x95a8, 0x8589, 0xf56e, 0xe54f, 0xd52c, 0xc50d,
  406.   0x34e2, 0x24c3, 0x14a0, 0x0481, 0x7466, 0x6447, 0x5424, 0x4405,
  407.   0xa7db, 0xb7fa, 0x8799, 0x97b8, 0xe75f, 0xf77e, 0xc71d, 0xd73c,
  408.   0x26d3, 0x36f2, 0x0691, 0x16b0, 0x6657, 0x7676, 0x4615, 0x5634,
  409.   0xd94c, 0xc96d, 0xf90e, 0xe92f, 0x99c8, 0x89e9, 0xb98a, 0xa9ab,
  410.   0x5844, 0x4865, 0x7806, 0x6827, 0x18c0, 0x08e1, 0x3882, 0x28a3,
  411.   0xcb7d, 0xdb5c, 0xeb3f, 0xfb1e, 0x8bf9, 0x9bd8, 0xabbb, 0xbb9a,
  412.   0x4a75, 0x5a54, 0x6a37, 0x7a16, 0x0af1, 0x1ad0, 0x2ab3, 0x3a92,
  413.   0xfd2e, 0xed0f, 0xdd6c, 0xcd4d, 0xbdaa, 0xad8b, 0x9de8, 0x8dc9,
  414.   0x7c26, 0x6c07, 0x5c64, 0x4c45, 0x3ca2, 0x2c83, 0x1ce0, 0x0cc1,
  415.   0xef1f, 0xff3e, 0xcf5d, 0xdf7c, 0xaf9b, 0xbfba, 0x8fd9, 0x9ff8,
  416.   0x6e17, 0x7e36, 0x4e55, 0x5e74, 0x2e93, 0x3eb2, 0x0ed1, 0x1ef0
  417. };
  418.  
  419. /*
  420.  * updcrc macro derived from article Copyright (C) 1986 Stephen Satchell.
  421.  *  NOTE: First srgument must be in range 0 to 255.
  422.  *        Second argument is referenced twice.
  423.  *
  424.  * Programmers may incorporate any or all code into their programs,
  425.  * giving proper credit within the source. Publication of the
  426.  * source routines is permitted so long as proper credit is given
  427.  * to Stephen Satchell, Satchell Evaluations and Chuck Forsberg,
  428.  * Omen Technology.
  429.  */
  430.  
  431. #define updcrc(cp, crc) ( crctab[((crc >> 8) & 255)] ^ (crc << 8) ^ cp)
  432.  
  433. /*
  434.  * Copyright (C) 1986 Gary S. Brown.  You may use this program, or
  435.  * code or tables extracted from it, as desired without restriction.
  436.  */
  437.  
  438. /*
  439.  * First, the polynomial itself and its table of feedback terms.  The
  440.  * polynomial is
  441.  * X^32+X^26+X^23+X^22+X^16+X^12+X^11+X^10+X^8+X^7+X^5+X^4+X^2+X^1+X^0
  442.  * Note that we take it "backwards" and put the highest-order term in
  443.  * the lowest-order bit.  The X^32 term is "implied"; the LSB is the
  444.  * X^31 term, etc.  The X^0 term (usually shown as "+1") results in
  445.  * the MSB being 1.
  446.  *
  447.  * Note that the usual hardware shift  implementation, which
  448.  * is what we're using (we're merely optimizing it by doing eight-bit
  449.  * chunks at a time) shifts bits into the lowest-order term.  In our
  450.  * implementation, that means shifting towards the right.  Why do we
  451.  * do it this way?  Because the calculated CRC must be transmitted in
  452.  * order from highest-order term to lowest-order term.  UARTs transmit
  453.  * characters in order from LSB to MSB.  By storing the CRC this way,
  454.  * we hand it to the UART in the order low-byte to high-byte; the UART
  455.  * sends each low-bit to hight-bit; and the result is transmission bit
  456.  * by bit from highest- to lowest-order term without requiring any bit
  457.  * shuffling on our part.  Reception works similarly.
  458.  */
  459.  
  460. /*
  461.  * The feedback terms table consists of 256, 32-bit entries.  Notes:
  462.  *
  463.  *     The table can be generated at runtime if desired; code to do so
  464.  *     is shown later.  It might not be obvious, but the feedback
  465.  *     terms simply represent the results of eight shift/xor opera-
  466.  *     tions for all combinations of data and CRC  values.
  467.  *
  468.  *     The values must be right-shifted by eight bits by the "updcrc"
  469.  *     logic; the shift must be unsigned (bring in zeroes).  On some
  470.  *     hardware you could probably optimize the shift in assembler by
  471.  *     using byte-swap instructions.
  472.  */
  473.  
  474. static unsigned long cr3tab[] =   /*
  475.                                    * CRC polynomial 0xedb88320
  476.                                    */
  477. {
  478.   0x00000000, 0x77073096, 0xee0e612c, 0x990951ba, 0x076dc419, 0x706af48f,
  479.   0xe963a535, 0x9e6495a3, 0x0edb8832, 0x79dcb8a4, 0xe0d5e91e, 0x97d2d988,
  480.   0x09b64c2b, 0x7eb17cbd, 0xe7b82d07, 0x90bf1d91, 0x1db71064, 0x6ab020f2,
  481.   0xf3b97148, 0x84be41de, 0x1adad47d, 0x6ddde4eb, 0xf4d4b551, 0x83d385c7,
  482.   0x136c9856, 0x646ba8c0, 0xfd62f97a, 0x8a65c9ec, 0x14015c4f, 0x63066cd9,
  483.   0xfa0f3d63, 0x8d080df5, 0x3b6e20c8, 0x4c69105e, 0xd56041e4, 0xa2677172,
  484.   0x3c03e4d1, 0x4b04d447, 0xd20d85fd, 0xa50ab56b, 0x35b5a8fa, 0x42b2986c,
  485.   0xdbbbc9d6, 0xacbcf940, 0x32d86ce3, 0x45df5c75, 0xdcd60dcf, 0xabd13d59,
  486.   0x26d930ac, 0x51de003a, 0xc8d75180, 0xbfd06116, 0x21b4f4b5, 0x56b3c423,
  487.   0xcfba9599, 0xb8bda50f, 0x2802b89e, 0x5f058808, 0xc60cd9b2, 0xb10be924,
  488.   0x2f6f7c87, 0x58684c11, 0xc1611dab, 0xb6662d3d, 0x76dc4190, 0x01db7106,
  489.   0x98d220bc, 0xefd5102a, 0x71b18589, 0x06b6b51f, 0x9fbfe4a5, 0xe8b8d433,
  490.   0x7807c9a2, 0x0f00f934, 0x9609a88e, 0xe10e9818, 0x7f6a0dbb, 0x086d3d2d,
  491.   0x91646c97, 0xe6635c01, 0x6b6b51f4, 0x1c6c6162, 0x856530d8, 0xf262004e,
  492.   0x6c0695ed, 0x1b01a57b, 0x8208f4c1, 0xf50fc457, 0x65b0d9c6, 0x12b7e950,
  493.   0x8bbeb8ea, 0xfcb9887c, 0x62dd1ddf, 0x15da2d49, 0x8cd37cf3, 0xfbd44c65,
  494.   0x4db26158, 0x3ab551ce, 0xa3bc0074, 0xd4bb30e2, 0x4adfa541, 0x3dd895d7,
  495.   0xa4d1c46d, 0xd3d6f4fb, 0x4369e96a, 0x346ed9fc, 0xad678846, 0xda60b8d0,
  496.   0x44042d73, 0x33031de5, 0xaa0a4c5f, 0xdd0d7cc9, 0x5005713c, 0x270241aa,
  497.   0xbe0b1010, 0xc90c2086, 0x5768b525, 0x206f85b3, 0xb966d409, 0xce61e49f,
  498.   0x5edef90e, 0x29d9c998, 0xb0d09822, 0xc7d7a8b4, 0x59b33d17, 0x2eb40d81,
  499.   0xb7bd5c3b, 0xc0ba6cad, 0xedb88320, 0x9abfb3b6, 0x03b6e20c, 0x74b1d29a,
  500.   0xead54739, 0x9dd277af, 0x04db2615, 0x73dc1683, 0xe3630b12, 0x94643b84,
  501.   0x0d6d6a3e, 0x7a6a5aa8, 0xe40ecf0b, 0x9309ff9d, 0x0a00ae27, 0x7d079eb1,
  502.   0xf00f9344, 0x8708a3d2, 0x1e01f268, 0x6906c2fe, 0xf762575d, 0x806567cb,
  503.   0x196c3671, 0x6e6b06e7, 0xfed41b76, 0x89d32be0, 0x10da7a5a, 0x67dd4acc,
  504.   0xf9b9df6f, 0x8ebeeff9, 0x17b7be43, 0x60b08ed5, 0xd6d6a3e8, 0xa1d1937e,
  505.   0x38d8c2c4, 0x4fdff252, 0xd1bb67f1, 0xa6bc5767, 0x3fb506dd, 0x48b2364b,
  506.   0xd80d2bda, 0xaf0a1b4c, 0x36034af6, 0x41047a60, 0xdf60efc3, 0xa867df55,
  507.   0x316e8eef, 0x4669be79, 0xcb61b38c, 0xbc66831a, 0x256fd2a0, 0x5268e236,
  508.   0xcc0c7795, 0xbb0b4703, 0x220216b9, 0x5505262f, 0xc5ba3bbe, 0xb2bd0b28,
  509.   0x2bb45a92, 0x5cb36a04, 0xc2d7ffa7, 0xb5d0cf31, 0x2cd99e8b, 0x5bdeae1d,
  510.   0x9b64c2b0, 0xec63f226, 0x756aa39c, 0x026d930a, 0x9c0906a9, 0xeb0e363f,
  511.   0x72076785, 0x05005713, 0x95bf4a82, 0xe2b87a14, 0x7bb12bae, 0x0cb61b38,
  512.   0x92d28e9b, 0xe5d5be0d, 0x7cdcefb7, 0x0bdbdf21, 0x86d3d2d4, 0xf1d4e242,
  513.   0x68ddb3f8, 0x1fda836e, 0x81be16cd, 0xf6b9265b, 0x6fb077e1, 0x18b74777,
  514.   0x88085ae6, 0xff0f6a70, 0x66063bca, 0x11010b5c, 0x8f659eff, 0xf862ae69,
  515.   0x616bffd3, 0x166ccf45, 0xa00ae278, 0xd70dd2ee, 0x4e048354, 0x3903b3c2,
  516.   0xa7672661, 0xd06016f7, 0x4969474d, 0x3e6e77db, 0xaed16a4a, 0xd9d65adc,
  517.   0x40df0b66, 0x37d83bf0, 0xa9bcae53, 0xdebb9ec5, 0x47b2cf7f, 0x30b5ffe9,
  518.   0xbdbdf21c, 0xcabac28a, 0x53b39330, 0x24b4a3a6, 0xbad03605, 0xcdd70693,
  519.   0x54de5729, 0x23d967bf, 0xb3667a2e, 0xc4614ab8, 0x5d681b02, 0x2a6f2b94,
  520.   0xb40bbe37, 0xc30c8ea1, 0x5a05df1b, 0x2d02ef8d
  521. };
  522.  
  523. #define UPDC32(b, c) (cr3tab[((int)c ^ b) & 0xff] ^ ((c >> 8) & 0x00FFFFFF))
  524.  
  525. static char *frametypes[] =
  526. {
  527.   "CARRIER_LOST",                 /*
  528.                                    * -3
  529.                                    */
  530.   "TIMEOUT",                      /*
  531.                                    * -2
  532.                                    */
  533.   "ERROR",                        /*
  534.                                    * -1
  535.                                    */
  536. #define FTOFFSET 3
  537.   "ZRQINIT",
  538.   "ZRINIT",
  539.   "ZSINIT",
  540.   "ZACK",
  541.   "ZFILE",
  542.   "ZSKIP",
  543.   "ZNAK",
  544.   "ZABORT",
  545.   "ZFIN",
  546.   "ZRPOS",
  547.   "ZDATA",
  548.   "ZEOF",
  549.   "ZFERR",
  550.   "ZCRC",
  551.   "ZCHALLENGE",
  552.   "ZCOMPL",
  553.   "ZCAN",
  554.   "ZFREECNT",
  555.   "ZCOMMAND",
  556.   "ZSTDERR",
  557.   "xxxxx"
  558. #define FRTYPES 22                /*
  559.                                    * Total number of frame types in this
  560.                                    * array
  561.                                    */
  562.                         /*
  563.                          * not including psuedo negative entries
  564.                          */
  565. };
  566.  
  567. /**********************************************************
  568.  *      void zsbhdr(struct Vars *v, USHORT type)
  569.  *
  570.  * Send ZMODEM binary header hdr of type type
  571.  **********************************************************/
  572. void
  573. zsbhdr(struct Vars *v, USHORT type)
  574. {
  575.   UBYTE    *hdr = v->Txhdr;
  576.   short     n;
  577.   USHORT    crc;
  578.   ULONG     crc32;
  579.  
  580.   xsendline(v, ZPAD);
  581.   xsendline(v, ZDLE);
  582.  
  583.   if (v->Crc32t = v->Txfcs32)   /*
  584.                                  * zsbh32()
  585.                                  */
  586.     {
  587.       xsendline(v, ZBIN32);
  588.       zsendline(v, (UBYTE) type);
  589.  
  590.       crc32 = 0xFFFFFFFFL;
  591.       crc32 = UPDC32(type, crc32);
  592.  
  593.       for (n = 4; --n >= 0; ++hdr)
  594.         {
  595.           crc32 = UPDC32((0377 & *hdr), crc32);
  596.           zsendline(v, *hdr);
  597.         }
  598.       crc32 = ~crc32;
  599.       for (n = 4; --n >= 0;)
  600.         {
  601.           zsendline(v, (int) crc32);
  602.           crc32 >>= 8;
  603.         }
  604.     }
  605.   else
  606.     {
  607.       xsendline(v, ZBIN);
  608.       zsendline(v, (UBYTE) type);
  609.  
  610.       crc = updcrc(type, 0);
  611.       for (n = 4; --n >= 0;)
  612.         {
  613.           zsendline(v, *hdr);
  614.           crc = updcrc(((USHORT) (*hdr++)), crc);
  615.         }
  616.  
  617.       crc = updcrc(((USHORT) 0), crc);
  618.       crc = updcrc(((USHORT) 0), crc);
  619.       zsendline(v, (UBYTE) (crc >> 8));
  620.       zsendline(v, (UBYTE) crc);
  621.     }
  622. }       /*
  623.          * End of void zsbhdr()
  624.          */
  625.  
  626. /**********************************************************
  627.  *      void zshhdr(struct Vars *v, USHORT type)
  628.  *
  629.  * Send ZMODEM HEX header hdr of type type
  630.  **********************************************************/
  631. void
  632. zshhdr(struct Vars *v, USHORT type)
  633. {
  634.   UBYTE    *hdr = v->Txhdr;
  635.   short     n;
  636.   USHORT    crc;
  637.  
  638.   sendline(v, ZPAD);
  639.   sendline(v, ZPAD);
  640.   sendline(v, ZDLE);
  641.   sendline(v, ZHEX);
  642.   zputhex(v, (UBYTE) type);
  643.   v->Crc32t = 0;
  644.  
  645.   crc = updcrc(type, 0);
  646.   for (n = 4; --n >= 0;)
  647.     {
  648.       zputhex(v, *hdr);
  649.       crc = updcrc(((USHORT) (*hdr++)), crc);
  650.     }
  651.  
  652.   crc = updcrc(((USHORT) 0), crc);
  653.   crc = updcrc(((USHORT) 0), crc);
  654.   zputhex(v, (UBYTE) (crc >> 8));
  655.   zputhex(v, (UBYTE) crc);
  656.  
  657. /*
  658.  * Make it printable on remote machine
  659.  */
  660.   sendline(v, '\r');
  661.   sendline(v, '\n');
  662. /*
  663.  * Uncork the remote in case a fake XOFF has stopped data flow
  664.  */
  665.   if (type != ZFIN)
  666.     sendline(v, ZM_XON);
  667. }       /*
  668.          * End of void zshhdr()
  669.          */
  670.  
  671. /**********************************************************
  672.  *      void zsdata() and void zsda32()
  673.  *
  674.  * Send binary array buf of length length, with ending
  675.  * ZDLE sequence frameend
  676.  **********************************************************/
  677.  
  678. void
  679. zsdata(struct Vars *v, short length, USHORT frameend)
  680. {
  681.   UBYTE    *buf;
  682.  
  683.   buf = v->Pktbuf;
  684.  
  685.   if (v->Crc32t)
  686.     {
  687.       short     c;
  688.       ULONG     crc;
  689.  
  690.       crc = 0xFFFFFFFFL;
  691.       for (; --length >= 0; ++buf)
  692.         {
  693.           c = *buf;
  694.           if (c & 0140)
  695.             xsendline(v, v->Lastzsent = c);
  696.           else
  697.             zsendline(v, c);
  698.           crc = UPDC32(c, crc);
  699.         }
  700.       xsendline(v, ZDLE);
  701.       xsendline(v, frameend);
  702.       crc = UPDC32(frameend, crc);
  703.  
  704.       crc = ~crc;
  705.       for (c = 4; --c >= 0;)
  706.         {
  707.           zsendline(v, (int) crc);
  708.           crc >>= 8;
  709.         }
  710.     }
  711.   else
  712.     {
  713.       unsigned short crc;
  714.  
  715.       crc = 0;
  716.       for (; --length >= 0; ++buf)
  717.         {
  718.           zsendline(v, *buf);
  719.           crc = updcrc(*buf, crc);
  720.         }
  721.       xsendline(v, ZDLE);
  722.       xsendline(v, frameend);
  723.       crc = updcrc(frameend, crc);
  724.  
  725.       crc = updcrc(0, updcrc(0, crc));
  726.       zsendline(v, crc >> 8);
  727.       zsendline(v, crc);
  728.     }
  729.   if (frameend == ZCRCW)
  730.     {
  731.       xsendline(v, ZM_XON);
  732.     }
  733. }       /*
  734.          * End of void zsdata()
  735.          */
  736.  
  737. /**********************************************************
  738.  *      short zrdata(struct Vars *v, UBYTE *buf, short length)
  739.  *
  740.  * Receive array buf of max length with ending ZDLE sequence
  741.  * and CRC-16.  Returns the ending character or error code.
  742.  **********************************************************/
  743. short
  744. zrdata(struct Vars *v, UBYTE *buf, short length)
  745. {
  746.   short     c,
  747.             d;
  748.   USHORT    crc;
  749.  
  750.   if (v->Rxframeind == ZBIN32)
  751.     return zrdat32(v, buf, length);
  752.  
  753.   crc = v->Rxcount = 0;
  754.   for (;;)
  755.     {
  756.       if ((c = zdlread(v)) & ~0xFF)
  757.         {
  758.         crcfoo:
  759.           switch (c)
  760.             {
  761.               case GOTCRCE:
  762.               case GOTCRCG:
  763.               case GOTCRCQ:
  764.               case GOTCRCW:
  765.                 crc = updcrc(((d = c) & 0xFF), crc);
  766.                 if ((c = zdlread(v)) & ~0xFF)
  767.                   goto crcfoo;
  768.                 crc = updcrc(c, crc);
  769.                 if ((c = zdlread(v)) & ~0xFF)
  770.                   goto crcfoo;
  771.                 crc = updcrc(c, crc);
  772.                 if (crc & 0xFFFF)
  773.                   {
  774.                     strcpy(v->Msgbuf, "MSG_BAD_DATA_CRC16");
  775.                     return ZM_ERROR;
  776.                   }
  777.                 return d;
  778.               case GOTCAN:
  779.                 strcpy(v->Msgbuf, "MSG_SENDER_CANCELED");
  780.                 return ZCAN;
  781.               case TIMEOUT:
  782.                 strcpy(v->Msgbuf, "MSG_DATA_PACKET_TIMEOUT_TXT");
  783.                 return c;
  784.               case RCDO:
  785.                 return c;
  786.               default:
  787.                 strcpy(v->Msgbuf, "MSG_UNRECOGNIZABLE_DATA_PACKET_TXT");
  788.                 return c;
  789.             }
  790.         }
  791.       if (--length < 0)
  792.         {
  793.           strcpy(v->Msgbuf, "MSG_DATA_PACKET_TOO_LONG_TXT");
  794.           return ZM_ERROR;
  795.         }
  796.       ++v->Rxcount;
  797.       *buf++ = c;
  798.       crc = updcrc(c, crc);
  799.       continue;
  800.     }
  801. }       /*
  802.          * End of short zrdata()
  803.          */
  804.  
  805. /**********************************************************
  806.  *      short zrdat32(struct Vars *v, UBYTE *buf, short length)
  807.  *
  808.  * Receive array buf of max length with ending ZDLE sequence
  809.  * and CRC-32.  Returns the ending character or error code.
  810.  **********************************************************/
  811. short
  812. zrdat32(struct Vars *v, UBYTE *buf, short length)
  813. {
  814.   short     c,
  815.             d;
  816.   ULONG     crc32;
  817.  
  818.   crc32 = 0xFFFFFFFFL;
  819.   v->Rxcount = 0;
  820.  
  821.   for (;;)
  822.     {
  823.       if ((c = zdlread(v)) & ~0xFF)
  824.         {
  825.         crcfoo:
  826.           switch (c)
  827.             {
  828.               case GOTCRCE:
  829.               case GOTCRCG:
  830.               case GOTCRCQ:
  831.               case GOTCRCW:
  832.                 d = c;
  833.                 c &= 0xFF;
  834.                 crc32 = UPDC32(c, crc32);
  835.                 if ((c = zdlread(v)) & ~0xFF)
  836.                   goto crcfoo;
  837.                 crc32 = UPDC32(c, crc32);
  838.                 if ((c = zdlread(v)) & ~0xFF)
  839.                   goto crcfoo;
  840.                 crc32 = UPDC32(c, crc32);
  841.                 if ((c = zdlread(v)) & ~0xFF)
  842.                   goto crcfoo;
  843.                 crc32 = UPDC32(c, crc32);
  844.                 if ((c = zdlread(v)) & ~0xFF)
  845.                   goto crcfoo;
  846.                 crc32 = UPDC32(c, crc32);
  847.                 if (crc32 != 0xDEBB20E3)
  848.                   {
  849.                     strcpy(v->Msgbuf, "MSG_BAD_DATA_CRC32_TXT");
  850.                     return ZM_ERROR;
  851.                   }
  852.                 return d;
  853.               case GOTCAN:
  854.                 strcpy(v->Msgbuf, "MSG_SENDER_CANCELED_TXT");
  855.                 return ZCAN;
  856.               case TIMEOUT:
  857.                 strcpy(v->Msgbuf, "MSG_DATA_PACKET_TIMEOUT_TXT");
  858.                 return c;
  859.               case RCDO:
  860.                 return c;
  861.               default:
  862.                 strcpy(v->Msgbuf, "MSG_UNRECOGNIZABLE_DATA_PACKET_TXT");
  863.                 return c;
  864.             }
  865.         }
  866.       if (--length < 0)
  867.         {
  868.           strcpy(v->Msgbuf, "MSG_DATA_PACKET_TOO_LONG_TXT");
  869.           return ZM_ERROR;
  870.         }
  871.       ++v->Rxcount;
  872.       *buf++ = c;
  873.       crc32 = UPDC32(c, crc32);
  874.       continue;
  875.     }
  876. }       /*
  877.          * End of short zrdat32()
  878.          */
  879.  
  880. /**********************************************************
  881.  *      short zgethdr(struct Vars *v)
  882.  *
  883.  * Read a ZMODEM header to hdr, either binary or hex.
  884.  *  On success return type of header.
  885.  *  Otherwise return negative on error.
  886.  **********************************************************/
  887. short
  888. zgethdr(struct Vars *v)
  889. {
  890.   short     c,
  891.             cancount;
  892.   long      n;
  893.  
  894.   n = v->Baud;  /*
  895.                  * Max characters before start of frame
  896.                  */
  897.   cancount = 5;
  898. again:
  899.   v->Rxframeind = v->Rxtype = 0;
  900.   switch (c = noxrd7(v))
  901.     {
  902.       case RCDO:
  903.       case TIMEOUT:
  904.         goto fifi;
  905.       case ZM_CAN:
  906.         if (--cancount <= 0)
  907.           {
  908.             c = ZCAN;
  909.             goto fifi;
  910.           }
  911.       case ZPAD:        /*
  912.                          * This is what we want.
  913.                          */
  914.         break;
  915.       default:
  916.       agn2:
  917.         if (--n <= 0)
  918.           {
  919.             strcpy(v->Msgbuf, "MSG_HEADER_SEARCH_GARBAGE_COUNT_EXCEEDED_TXT");
  920.             return ZM_ERROR;
  921.           }
  922.         if (c != ZM_CAN)
  923.           cancount = 5;
  924.         goto again;
  925.     }
  926.   cancount = 5;
  927. splat:
  928.   switch (c = noxrd7(v))
  929.     {
  930.       case ZPAD:
  931.         goto splat;
  932.       case RCDO:
  933.       case TIMEOUT:
  934.         goto fifi;
  935.       default:
  936.         goto agn2;
  937.       case ZDLE:        /*
  938.                          * This is what we want.
  939.                          */
  940.         break;
  941.     }
  942.  
  943.   switch (c = noxrd7(v))
  944.     {
  945.       case RCDO:
  946.       case TIMEOUT:
  947.         goto fifi;
  948.       case ZBIN:
  949.         v->Rxframeind = ZBIN;
  950.         v->Crc32 = FALSE;
  951.         c = zrbhdr(v);
  952.         break;
  953.       case ZBIN32:
  954.         v->Crc32 = v->Rxframeind = ZBIN32;
  955.         c = zrbhdr32(v);
  956.         break;
  957.       case ZHEX:
  958.         v->Rxframeind = ZHEX;
  959.         v->Crc32 = FALSE;
  960.         c = zrhhdr(v);
  961.         break;
  962.       case ZM_CAN:
  963.         if (--cancount <= 0)
  964.           {
  965.             c = ZCAN;
  966.             goto fifi;
  967.           }
  968.         goto agn2;
  969.       default:
  970.         goto agn2;
  971.     }
  972.   v->Rxpos = rclhdr(v);
  973. fifi:
  974.   switch (c)
  975.     {
  976.       case GOTCAN:
  977.         c = ZCAN;
  978.       case ZNAK:
  979.       case ZCAN:
  980.       case ZM_ERROR:
  981.       case TIMEOUT:
  982.       case RCDO:
  983.         sprintf(v->Msgbuf, "%s %s ", frametypes[c + FTOFFSET],
  984.                   (c >= 0) ? "MSG_HEADER" : "MSG_ERROR");
  985.     }
  986.   return c;
  987. }       /*
  988.          * End of short zgethdr()
  989.          */
  990.  
  991. /**********************************************************
  992.  *      short zrbhdr(struct Vars *v)
  993.  *
  994.  * Receive a binary style header (type and position)
  995.  **********************************************************/
  996. short
  997. zrbhdr(struct Vars *v)
  998. {
  999.   UBYTE    *hdr = v->Rxhdr;
  1000.   short     c,
  1001.             n;
  1002.   USHORT    crc;
  1003.  
  1004.   if ((c = zdlread(v)) & ~0xFF)
  1005.     return c;
  1006.   v->Rxtype = c;
  1007.   crc = updcrc(c, 0);
  1008.  
  1009.   for (n = 4; --n >= 0;)
  1010.     {
  1011.       if ((c = zdlread(v)) & ~0xFF)
  1012.         return c;
  1013.       crc = updcrc(c, crc);
  1014.       *hdr++ = c;
  1015.     }
  1016.   if ((c = zdlread(v)) & ~0xFF)
  1017.     return c;
  1018.   crc = updcrc(c, crc);
  1019.   if ((c = zdlread(v)) & ~0xFF)
  1020.     return c;
  1021.   crc = updcrc(c, crc);
  1022.   if (crc & 0xFFFF)
  1023.     {
  1024.       strcpy(v->Msgbuf, "MSG_BAD_HEADER_CRC16_TXT");
  1025.       return ZM_ERROR;
  1026.     }
  1027.   return v->Rxtype;
  1028. }       /*
  1029.          * End of short zrbhdr()
  1030.          */
  1031.  
  1032. /**********************************************************
  1033.  *      short zrbhdr32(struct Vars *v)
  1034.  *
  1035.  * Receive a binary style header (type and position) with
  1036.  * 32 bit FCS
  1037.  **********************************************************/
  1038. short
  1039. zrbhdr32(struct Vars *v)
  1040. {
  1041.   UBYTE    *hdr = v->Rxhdr;
  1042.   short     c,
  1043.             n;
  1044.   ULONG     crc32;
  1045.  
  1046.   if ((c = zdlread(v)) & ~0xFF)
  1047.     return c;
  1048.   v->Rxtype = c;
  1049.   crc32 = 0xFFFFFFFFL;
  1050.   crc32 = UPDC32(c, crc32);
  1051.  
  1052.   for (n = 4; --n >= 0;)
  1053.     {
  1054.       if ((c = zdlread(v)) & ~0xFF)
  1055.         return c;
  1056.       crc32 = UPDC32(c, crc32);
  1057.       *hdr++ = c;
  1058.     }
  1059.   for (n = 4; --n >= 0;)
  1060.     {
  1061.       if ((c = zdlread(v)) & ~0xFF)
  1062.         return c;
  1063.       crc32 = UPDC32(c, crc32);
  1064.     }
  1065.   if (crc32 != 0xDEBB20E3)
  1066.     {
  1067.       strcpy(v->Msgbuf, "MSG_BAD_HEADER_CRC32_TXT");
  1068.       return ZM_ERROR;
  1069.     }
  1070.   return v->Rxtype;
  1071. }       /*
  1072.          * End of short zrbhdr32()
  1073.          */
  1074.  
  1075. /**********************************************************
  1076.  *      short zrhhdr(struct Vars *v)
  1077.  *
  1078.  * Receive a hex style header (type and position)
  1079.  **********************************************************/
  1080. short
  1081. zrhhdr(struct Vars *v)
  1082. {
  1083.   UBYTE    *hdr = v->Rxhdr;
  1084.   short     c,
  1085.             n;
  1086.   USHORT    crc;
  1087.  
  1088.   if ((c = zgethex(v)) < 0)
  1089.     return c;
  1090.   v->Rxtype = c;
  1091.   crc = updcrc(c, 0);
  1092.  
  1093.   for (n = 4; --n >= 0;)
  1094.     {
  1095.       if ((c = zgethex(v)) < 0)
  1096.         return c;
  1097.       crc = updcrc(c, crc);
  1098.       *hdr++ = c;
  1099.     }
  1100.   if ((c = zgethex(v)) < 0)
  1101.     return c;
  1102.   crc = updcrc(c, crc);
  1103.   if ((c = zgethex(v)) < 0)
  1104.     return c;
  1105.   crc = updcrc(c, crc);
  1106.   if (crc & 0xFFFF)
  1107.     {
  1108.       strcpy(v->Msgbuf, "MSG_BAD_HEADER_CRC_TXT");
  1109.       return ZM_ERROR;
  1110.     }
  1111.   if (readock(v, 1) == '\r')
  1112.     readock(v, 1);      /*
  1113.                          * Throw away possible cr/lf
  1114.                          */
  1115.   return v->Rxtype;
  1116. }       /*
  1117.          * End of short zrhhdr()
  1118.          */
  1119.  
  1120. /**********************************************************
  1121.  *      void zputhex(struct Vars *v, UBYTE c)
  1122.  *
  1123.  * Send a byte as two hex digits
  1124.  **********************************************************/
  1125. void
  1126. zputhex(struct Vars *v, UBYTE c)
  1127. {
  1128.   static char digits[] = "0123456789abcdef";
  1129.  
  1130.   sendline(v, digits[(c >> 4) & 0x0F]);
  1131.   sendline(v, digits[c & 0x0F]);
  1132. }       /*
  1133.          * End of void zputhex()
  1134.          */
  1135.  
  1136. /**********************************************************
  1137.  *      void zsendline(struct Vars *v, UBYTE c)
  1138.  *
  1139.  * Send character c with ZMODEM escape sequence encoding.
  1140.  * Escape ZDLE, real DLE, XON, XOFF, and CR following @ (Telenet net escape)
  1141.  **********************************************************/
  1142. void
  1143. zsendline(struct Vars *v, UBYTE c)
  1144. {
  1145.   static char actions[256] =
  1146.   {
  1147.     3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 1, 3, 3,
  1148.     2, 2, 3, 2, 3, 3, 3, 3, 0, 3, 3, 3, 3, 3, 3, 3,
  1149.     3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3,
  1150.     3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3,
  1151.     3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3,
  1152.     3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3,
  1153.     3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3,
  1154.     3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3,
  1155.     3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 1, 3, 3,
  1156.     2, 2, 3, 2, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3,
  1157.     3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3,
  1158.     3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3,
  1159.     3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3,
  1160.     3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3,
  1161.     3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3,
  1162.     3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3
  1163.   };
  1164.  
  1165.   switch (actions[c])
  1166.     {
  1167.       case 0:
  1168.         xsendline(v, ZDLE);
  1169.         xsendline(v, v->Lastzsent = (c ^ 0100));
  1170.         break;
  1171.  
  1172.       case 1:
  1173.         if (!v->Zctlesc && (v->Lastzsent & 0177) != '@')
  1174.           goto sendit;
  1175.  
  1176.    /*
  1177.     * **** FALL THRU TO ****
  1178.     */
  1179.  
  1180.       case 2:
  1181.         xsendline(v, ZDLE);
  1182.         c ^= 0100;
  1183.  
  1184.       sendit:xsendline(v, v->Lastzsent = c);
  1185.         break;
  1186.  
  1187.       case 3:
  1188.         if (v->Zctlesc && !(c & 0140))
  1189.           {
  1190.             xsendline(v, ZDLE);
  1191.             c ^= 0100;
  1192.           }
  1193.  
  1194.         xsendline(v, v->Lastzsent = c);
  1195.         break;
  1196.     }
  1197. }       /*
  1198.          * End of void zsendline()
  1199.          */
  1200.  
  1201. /**********************************************************
  1202.  *      short zgethex(struct Vars *v)
  1203.  *
  1204.  * Decode two lower case hex digits into an 8 bit byte value
  1205.  **********************************************************/
  1206. short
  1207. zgethex(struct Vars *v)
  1208. {
  1209.   short     c,
  1210.             n;
  1211.  
  1212.   if ((n = noxrd7(v)) < 0)
  1213.     return n;
  1214.   n -= '0';
  1215.   if (n > 9)
  1216.     n -= ('a' - ':');
  1217.   if (n & ~0xF)
  1218.     return ZM_ERROR;
  1219.  
  1220.   if ((c = noxrd7(v)) < 0)
  1221.     return c;
  1222.   c -= '0';
  1223.   if (c > 9)
  1224.     c -= ('a' - ':');
  1225.   if (c & ~0xF)
  1226.     return ZM_ERROR;
  1227.  
  1228.   return (short) (n << 4 | c);
  1229. }       /*
  1230.          * End of short zgethex()
  1231.          */
  1232.  
  1233. /**********************************************************
  1234.  *      short zdlread(struct Vars *v)
  1235.  *
  1236.  * Read a byte, checking for ZMODEM escape encoding
  1237.  * including CAN*5 which represents a quick abort.
  1238.  **********************************************************/
  1239. short
  1240. zdlread(struct Vars *v)
  1241. {
  1242.   short     c;
  1243.  
  1244. again:
  1245. /*
  1246.  * Quick check for non control characters
  1247.  */
  1248.   if ((c = readock(v, v->Rxtimeout)) & 0140)
  1249.     return c;
  1250.   switch (c)
  1251.     {
  1252.       case ZDLE:
  1253.         break;
  1254.       case 023:
  1255.       case 0223:
  1256.       case 021:
  1257.       case 0221:
  1258.         goto again;
  1259.       default:
  1260.         if (v->Zctlesc && !(c & 0140))
  1261.           {
  1262.             goto again;
  1263.           }
  1264.         return c;
  1265.     }
  1266. again2:
  1267.   if ((c = readock(v, v->Rxtimeout)) < 0)
  1268.     return c;
  1269.   if (c == ZM_CAN && (c = readock(v, v->Rxtimeout)) < 0)
  1270.     return c;
  1271.   if (c == ZM_CAN && (c = readock(v, v->Rxtimeout)) < 0)
  1272.     return c;
  1273.   if (c == ZM_CAN && (c = readock(v, v->Rxtimeout)) < 0)
  1274.     return c;
  1275.   switch (c)
  1276.     {
  1277.       case ZM_CAN:
  1278.         return GOTCAN;
  1279.       case ZCRCE:
  1280.       case ZCRCG:
  1281.       case ZCRCQ:
  1282.       case ZCRCW:
  1283.         return ((short) (c | GOTOR));
  1284.       case ZRUB0:
  1285.         return 0177;
  1286.       case ZRUB1:
  1287.         return 0377;
  1288.       case 023:
  1289.       case 0223:
  1290.       case 021:
  1291.       case 0221:
  1292.         goto again2;
  1293.       default:
  1294.         if (v->Zctlesc && !(c & 0140))
  1295.           {
  1296.             goto again2;
  1297.           }
  1298.         if ((c & 0140) == 0100)
  1299.           return ((short) (c ^ 0100));
  1300.         break;
  1301.     }
  1302.   strcpy(v->Msgbuf, "MSG_BAD_ZMODEM_ESC_TXT");
  1303.   return ZM_ERROR;
  1304. }       /*
  1305.          * End of short zdlread()
  1306.          */
  1307.  
  1308. /**********************************************************
  1309.  *      short noxrd7(struct Vars *v)
  1310.  *
  1311.  * Read a character from the modem line with timeout.
  1312.  * Eat parity, XON and XOFF characters.
  1313.  **********************************************************/
  1314. short
  1315. noxrd7(struct Vars *v)
  1316. {
  1317.   short     c;
  1318.  
  1319.   for (;;)
  1320.     {
  1321.       if ((c = readock(v, v->Rxtimeout)) < 0)
  1322.         return c;
  1323.       switch (c &= 0x7F)
  1324.         {
  1325.           case ZM_XON:
  1326.           case ZM_XOFF:
  1327.             continue;
  1328.           default:
  1329.             if (v->Zctlesc && !(c & 0140))
  1330.               continue;
  1331.           case '\r':
  1332.           case '\n':
  1333.           case ZDLE:
  1334.             return c;
  1335.         }
  1336.     }
  1337. }       /*
  1338.          * short noxrd7()
  1339.          */
  1340.  
  1341. /**********************************************************
  1342.  *      void stohdr(struct Vars *v, long pos)
  1343.  *
  1344.  * Store long integer pos in Txhdr
  1345.  **********************************************************/
  1346. void
  1347. stohdr(struct Vars *v, long pos)
  1348. {
  1349.   v->Txhdr[ZP0] = pos;
  1350.   pos >>= 8;
  1351.   v->Txhdr[ZP1] = pos;
  1352.   pos >>= 8;
  1353.   v->Txhdr[ZP2] = pos;
  1354.   pos >>= 8;
  1355.   v->Txhdr[ZP3] = pos;
  1356. }       /*
  1357.          * End of void stohdr()
  1358.          */
  1359.  
  1360. /**********************************************************
  1361.  *      long rclhdr(struct Vars *v)
  1362.  *
  1363.  * Recover a long integer from a header
  1364.  **********************************************************/
  1365. long
  1366. rclhdr(struct Vars *v)
  1367. {
  1368.   long      l;
  1369.  
  1370.   l = v->Rxhdr[ZP3];
  1371.   l = (l << 8) | v->Rxhdr[ZP2];
  1372.   l = (l << 8) | v->Rxhdr[ZP1];
  1373.   l = (l << 8) | v->Rxhdr[ZP0];
  1374.   return l;
  1375. }       /*
  1376.          * End of long rclhdr()
  1377.          */
  1378.  
  1379. /**
  1380.    Find the end of the string.
  1381. **/
  1382. char     *
  1383. find_end(char *buf)
  1384. {
  1385.   while (*buf)
  1386.     buf++;
  1387.   return (buf);
  1388. }
  1389.  
  1390. /**
  1391.  Convert octal number to decimal.
  1392. **/
  1393. unsigned long
  1394. from_octal(char *buf)
  1395. {
  1396.   unsigned long value = 0;
  1397.   UBYTE     c;
  1398.  
  1399.   while (c = *buf)
  1400.     {
  1401.       if (c == ' ' || c == ',' || c == '\t' || c == '\r' || c == '\n')
  1402.         buf++;
  1403.       else
  1404.         break;
  1405.     }
  1406.  
  1407.   while (c = *buf++)
  1408.     {
  1409.       if (c >= '0' && c <= '7')
  1410.         value = (value << 3) + (c - '0');
  1411.       else
  1412.         break;
  1413.     }
  1414.  
  1415.   return (value);
  1416. }
  1417.  
  1418. /*
  1419.  * Skip all blanks.
  1420.  */
  1421. char     *
  1422. skip_chars(char *buf)
  1423. {
  1424.   UBYTE     c;
  1425.  
  1426.   while (c = *buf)
  1427.     {
  1428.       if (c == ' ' || c == ',' || c == '\t' || c == '\r' || c == '\n')
  1429.         {
  1430.           buf++;
  1431.  
  1432.           while (c = *buf)
  1433.             {
  1434.               if (c == ' ' || c == ',' || c == '\t' || c == '\r' || c == '\n')
  1435.                 buf++;
  1436.               else
  1437.                 return (buf);
  1438.             }
  1439.  
  1440.           return (buf);
  1441.         }
  1442.       else
  1443.         buf++;
  1444.     }
  1445.  
  1446.   return (buf);
  1447. }
  1448.  
  1449. /**********************************************************
  1450.  *      long XProtocolReceive(struct XPR_IO *xio)
  1451.  *
  1452.  * Main file reception routine; called by comm program
  1453.  **********************************************************/
  1454. long
  1455. XProtocolReceive(struct XPR_IO *xio)
  1456. {
  1457.   struct SetupVars *sv;
  1458.   struct Vars *v;
  1459.   UBYTE     err = FALSE;
  1460.  
  1461. /*
  1462.  * Perform common setup and initializations
  1463.  */
  1464.   if (!(v = setup(xio)))
  1465.     return XPRS_FAILURE;
  1466.  
  1467. /*
  1468.  * Remember data direction for cps rate calculation.
  1469.  */
  1470.   v->Receiving = TRUE;
  1471.   v->Tryzhdrtype = ZRINIT;
  1472.   v->Rxtimeout = 100;
  1473.  
  1474.   sv = (void *) v->io.xpr_data;
  1475.   if (sv->bufpos)
  1476.     {
  1477.       v->Modemchar = v->Modembuf;
  1478.       if (sv->buflen > sizeof(v->Modembuf))
  1479.         sv->buflen = sizeof(v->Modembuf);
  1480.       memcpy(v->Modembuf, sv->bufpos, sv->buflen);
  1481.       v->Modemcount = sv->buflen;
  1482.     }
  1483.  
  1484. /*
  1485.  * Transfer the files
  1486.  */
  1487.   if (rcvbatch(v) == ZM_ERROR)
  1488.     {
  1489.       upderr(v, "MSG_DOWNLOAD_CANCELLED_OR_TIMED_OUT");
  1490.       err = TRUE;
  1491.     }
  1492.   else
  1493.     updmsg(v, "MSG_DONE");
  1494.  
  1495. /*
  1496.  * Clean up and return
  1497.  * If an error occured, it's quite likely that there is * garbage in the
  1498.  * receive buffer we don't want the user * to see.
  1499.  */
  1500.   xpr_sflush ();
  1501.  
  1502.   FreeMem(v->Filebuf, v->Filebufmax);
  1503.   FreeMem(v, (long) sizeof(struct Vars));
  1504.  
  1505.   return (err) ? XPRS_FAILURE : XPRS_SUCCESS;
  1506. }       /*
  1507.          * End of long XProtocolReceive()
  1508.          */
  1509.  
  1510. /**********************************************************
  1511.  *      short rcvbatch(struct Vars *v)
  1512.  *
  1513.  * Start the batch transfer
  1514.  **********************************************************/
  1515. short
  1516. rcvbatch(struct Vars *v)
  1517. {
  1518.   switch (tryz(v))
  1519.     {
  1520.       case ZCOMPL:
  1521.         return OK;
  1522.       case ZFILE:
  1523.         if (rzfiles(v) == OK)
  1524.           return OK;
  1525.     }
  1526.   canit(v);
  1527.   return ZM_ERROR;
  1528. }       /*
  1529.          * End of short rcvbatch()
  1530.          */
  1531.  
  1532. /**********************************************************
  1533.  *      short tryz(struct Vars *v)
  1534.  *
  1535.  * Negotiate with sender to start a file transfer
  1536.  **********************************************************/
  1537. short
  1538. tryz(struct Vars *v)
  1539. {
  1540.   short     n,
  1541.             errors = 0;
  1542.   for (n = v->ErrorLimit; --n >= 0;)
  1543.     {
  1544.  /*
  1545.   * Set max frame length and capability flags
  1546.   */
  1547.       stohdr(v, (long) v->Tframlen);
  1548.       v->Txhdr[ZF0] = CANFC32 | CANFDX | CANOVIO;
  1549.  
  1550.       if (v->Zctlesc)
  1551.         v->Txhdr[ZF0] |= TESCCTL;
  1552.  
  1553.       zshhdr(v, v->Tryzhdrtype);
  1554.       sendbuf(v);
  1555.  
  1556.       if (v->Tryzhdrtype == ZSKIP)      /*
  1557.                                          * Don't skip too far.
  1558.                                          */
  1559.         v->Tryzhdrtype = ZRINIT;        /*
  1560.                                          * CAF 8-21-87
  1561.                                          */
  1562.  
  1563.     again:
  1564.  /*
  1565.   * Check for abort from comm program
  1566.   */
  1567.  
  1568.           if ( xpr_chkabort() )
  1569.             {
  1570.               zshhdr(v, ZABORT);
  1571.               sendbuf(v);
  1572.               return ZM_ERROR;
  1573.             }
  1574.  
  1575.       switch (zgethdr(v))
  1576.         {
  1577.           case ZFILE:   /*
  1578.                          * File name and info packet
  1579.                          */
  1580.             v->Zconv = v->Rxhdr[ZF0];   /*
  1581.                                          * Suggested txt mode; ZCNL = text,
  1582.                                          */
  1583.        /*
  1584.         * ZCBIN = binary, 0 = don't know.
  1585.         */
  1586.             v->Zmanag = v->Rxhdr[ZF1];  /*
  1587.                                          * Suggested file management mode.
  1588.                                          */
  1589.             v->Ztrans = v->Rxhdr[ZF2];  /*
  1590.                                          * Suggested file transport mode.
  1591.                                          */
  1592.             v->Tryzhdrtype = ZRINIT;
  1593.  
  1594.             if (zrdata(v, v->Pktbuf, v->ksize) == GOTCRCW)
  1595.               return ZFILE;
  1596.             zshhdr(v, ZNAK);    /*
  1597.                                  * Packet mangled, ask for retry
  1598.                                  */
  1599.             sendbuf(v);
  1600.             goto again;
  1601.           case ZSINIT:          /*
  1602.                                  * Special attention-grabbing string to use
  1603.                                  * to
  1604.                                  */
  1605.             v->Zctlesc = TESCCTL & v->Rxhdr[ZF0];
  1606.        /*
  1607.         * interrupt sender
  1608.         */
  1609.             if (zrdata(v, v->Attn, ZATTNLEN) == GOTCRCW)
  1610.               zshhdr(v, ZACK);
  1611.             else
  1612.               zshhdr(v, ZNAK);
  1613.             sendbuf(v);
  1614.             goto again;
  1615.           case ZFREECNT:        /*
  1616.                                  * Sender wants to know how much room we've
  1617.                                  * got
  1618.                                  */
  1619.             stohdr(v, getfree(v));
  1620.             zshhdr(v, ZACK);
  1621.             sendbuf(v);
  1622.             goto again;
  1623.           case ZCOMMAND:        /*
  1624.                                  * Sender wants us to do remote commands,
  1625.                                  */
  1626.        /*
  1627.         * but we don't do requests.
  1628.         */
  1629.  
  1630.             if (zrdata(v, v->Pktbuf, v->ksize) == GOTCRCW)
  1631.               {
  1632.                 sprintf(v->Msgbuf, "MSG_IGNORING_COMMAND", v->Pktbuf);
  1633.                 upderr(v, v->Msgbuf);   /*
  1634.                                          * Ignore and report all uploaded
  1635.                                          * commands
  1636.                                          */
  1637.                 stohdr(v, 0L);  /*
  1638.                                  * whilst telling sender they worked;
  1639.                                  */
  1640.                 do
  1641.                   {
  1642.                     zshhdr(v, ZCOMPL);  /*
  1643.                                          * paranoia can be good for you...
  1644.                                          */
  1645.                     sendbuf(v);
  1646.                   }
  1647.                 while (++errors < v->ErrorLimit && zgethdr(v) != ZFIN);
  1648.                 ackbibi(v);
  1649.                 return ZCOMPL;
  1650.               }
  1651.             else
  1652.               zshhdr(v, ZNAK);
  1653.             sendbuf(v);
  1654.             goto again;
  1655.           case ZCOMPL:
  1656.             goto again;
  1657.           case ZFIN:    /*
  1658.                          * Sender has ended batch
  1659.                          */
  1660.             ackbibi(v);
  1661.             return ZCOMPL;
  1662.           case ZCAN:
  1663.           case RCDO:
  1664.             upderr(v, v->Msgbuf);
  1665.             return ZM_ERROR;
  1666.         }
  1667.     }
  1668.   return ZM_ERROR;
  1669. }       /*
  1670.          * End of short tryz()
  1671.          */
  1672.  
  1673. /**********************************************************
  1674.  *      short rzfiles(struct Vars *v)
  1675.  *
  1676.  * Receive a batch of files
  1677.  **********************************************************/
  1678. short
  1679. rzfiles(struct Vars *v)
  1680. {
  1681.   struct SetupVars *sv;
  1682.   short     c;
  1683.  
  1684. /*
  1685.  * Keep receiving files until end of batch or error
  1686.  */
  1687.   while (TRUE)
  1688.     {
  1689.       switch (c = rzfile(v))
  1690.         {
  1691.           case ZEOF:
  1692.           case ZSKIP:
  1693.             switch (tryz(v))
  1694.               {
  1695.                 case ZCOMPL:
  1696.                   return OK;
  1697.                 default:
  1698.                   return ZM_ERROR;
  1699.                 case ZFILE:
  1700.                   break;
  1701.               }
  1702.             break;
  1703.           default:
  1704.             bfclose(v);
  1705.             sv = (void *) v->io.xpr_data;
  1706.             if (*sv->option_k == 'N' )
  1707.               {
  1708.                 updmsg(v, "MSG_DELETING_PARTIALLY_RECEIVED_FILE");
  1709.                 unlink(v->Filename);
  1710.               }
  1711.             else
  1712.               updmsg(v, "MSG_KEEPING_PARTIALLY_RECEIVED_FILE");
  1713.             return c;
  1714.         }
  1715.     }
  1716. }       /*
  1717.          * End of short rzfiles()
  1718.          */
  1719.  
  1720. /**********************************************************
  1721.  *      short rzfile(struct Vars *v)
  1722.  *
  1723.  * Receive one file; file name packet already read into
  1724.  * Pktbuf by tryz()
  1725.  **********************************************************/
  1726. short
  1727. rzfile(struct Vars *v)
  1728. {
  1729.   short     c,
  1730.             n;
  1731.   long      result = 0,
  1732.             abort = 0;
  1733.  
  1734. /*
  1735.  * Process file name packet; either open file and prepare to receive, * or
  1736.  * tell us to skip this one.
  1737.  */
  1738.   if (procheader(v) == ZM_ERROR)
  1739.     return v->Tryzhdrtype = ZSKIP;
  1740.  
  1741.   n = v->ErrorLimit;
  1742.   v->Rxbytes = v->Strtpos;
  1743.   v->Eofseen = FALSE;
  1744.  
  1745. /*
  1746.  * Receive ZDATA frames until finished
  1747.  */
  1748.   while (TRUE)
  1749.     {
  1750.       stohdr(v, v->Rxbytes);    /*
  1751.                                  * Tell sender where to start frame
  1752.                                  */
  1753.       zshhdr(v, ZRPOS);
  1754.       sendbuf(v);
  1755.     nxthdr:
  1756.  /*
  1757.   * Check for abort from comm program
  1758.   */
  1759.           if (abort)
  1760.             {
  1761.               result = abort;
  1762.               abort = 0;
  1763.             };
  1764.  
  1765.      /*
  1766.       * Cancel transmission.
  1767.       */
  1768.           if (result || xpr_chkabort() )
  1769.             {
  1770.               zshhdr(v, ZABORT);
  1771.               sendbuf(v);
  1772.             };
  1773.  
  1774.       switch (c = zgethdr(v))   /*
  1775.                                  * Wait for frame header
  1776.                                  */
  1777.         {
  1778.           default:
  1779.             return ZM_ERROR;
  1780.           case ZFIN:
  1781.             zshhdr(v, ZCOMPL);
  1782.             sendbuf(v);
  1783.             return ZFIN;
  1784.           case ZNAK:
  1785.           case TIMEOUT:
  1786.             if (--n < 0)
  1787.               return ZM_ERROR;
  1788.             v->xpru.xpru_updatemask = XPRU_ERRORMSG | XPRU_TIMEOUTS;
  1789.             sprintf(find_end(v->Msgbuf), "MSG_AT %ld RETRIES %ld LEFT",
  1790.                       v->Rxbytes, (long) n);
  1791.             v->xpru.xpru_errormsg = (char *) v->Msgbuf;
  1792.             ++v->xpru.xpru_timeouts;
  1793.             display_update(&v->xpru);
  1794.             continue;
  1795.           case ZFILE:   /*
  1796.                          * Sender didn't see our ZRPOS yet; try again
  1797.                          */
  1798.  
  1799.             zrdata(v, v->Pktbuf, v->ksize);     /*
  1800.                                                  * Read and discard
  1801.                                                  * redundant
  1802.                                                  */
  1803.             continue;   /*
  1804.                          * filename packet
  1805.                          */
  1806.           case ZEOF:    /*
  1807.                          * End of file data
  1808.                          */
  1809.             if (v->Rxpos != v->Rxbytes)         /*
  1810.                                                  * We aren't in sync; go
  1811.                                                  * back
  1812.                                                  */
  1813.               {
  1814.                 sprintf(v->Msgbuf, "MSG_BAD_EOF:%ld %ld",
  1815.                           v->Rxbytes, v->Rxpos);
  1816.                 upderr(v, v->Msgbuf);
  1817.                 continue;
  1818.               }
  1819.             bfclose(v);         /*
  1820.                                  * All done; close file
  1821.                                  */
  1822.             updmsg(v, "MSG_EOF_RECEIVED");
  1823.             return c;
  1824.           case ZM_ERROR:   /*
  1825.                          * Too much garbage while waiting for frame header
  1826.                          */
  1827.             if (--n < 0)
  1828.               return ZM_ERROR;
  1829.             v->xpru.xpru_updatemask = XPRU_ERRORMSG | XPRU_ERRORS;
  1830.             sprintf(find_end(v->Msgbuf), "MSG_AT %ld RETRIES %ld LEFT",
  1831.                       v->Rxbytes, (long) n);
  1832.             v->xpru.xpru_errormsg = (char *) v->Msgbuf;
  1833.             ++v->xpru.xpru_errors;
  1834.             display_update(&v->xpru);
  1835.             zmputs(v, v->Attn);
  1836.             continue;
  1837.           case ZSKIP:
  1838.             v->Modtime = 1;
  1839.             bfclose(v);
  1840.             upderr(v, "MSG_SKIP_COMMAND_RECEIVED");
  1841.             return (c);
  1842.           case ZDATA:   /*
  1843.                          * More file data packets forthcoming
  1844.                          */
  1845.             if (v->Rxpos != v->Rxbytes)         /*
  1846.                                                  * We aren't in sync; go
  1847.                                                  * back
  1848.                                                  */
  1849.               {
  1850.                 if (--n < 0)
  1851.                   return ZM_ERROR;
  1852.                 v->xpru.xpru_updatemask = XPRU_ERRORMSG | XPRU_ERRORS;
  1853.                 sprintf(v->Msgbuf, "MSG_DATA_AT %ld BAD_POSITION %ld",
  1854.                           v->Rxbytes, v->Rxpos);
  1855.                 v->xpru.xpru_errormsg = (char *) v->Msgbuf;
  1856.                 ++v->xpru.xpru_errors;
  1857.                 display_update(&v->xpru);
  1858.                 zmputs(v, v->Attn);
  1859.                 continue;
  1860.               }
  1861.        /*
  1862.         * Receive file data packet(s)
  1863.         */
  1864.           moredata:
  1865.        /*
  1866.         * Check for abort from comm program
  1867.         */
  1868.                 if( (abort = xpr_chkabort()) )
  1869.                   {
  1870.                     zshhdr(v, ZABORT);
  1871.                     sendbuf(v);
  1872.                     upderr(v, "MSG_TRANSFER_CANCELED");
  1873.                     return ZM_ERROR;
  1874.                   };
  1875.             switch (c = zrdata(v, v->Pktbuf, v->ksize))
  1876.               {
  1877.                 case ZCAN:
  1878.                 case RCDO:
  1879.                   upderr(v, "MSG_TRANSFER_CANCELED");
  1880.                   return ZM_ERROR;
  1881.                 case ZM_ERROR:     /*
  1882.                                  * CRC error or packet too long
  1883.                                  */
  1884.                   if (--n < 0)
  1885.                     return ZM_ERROR;
  1886.                   v->xpru.xpru_updatemask = XPRU_ERRORMSG | XPRU_ERRORS;
  1887.                   sprintf(find_end(v->Msgbuf), "MSG_AT %ld RETRIES %ld LEFT",
  1888.                             v->Rxbytes, (long) n);
  1889.                   v->xpru.xpru_errormsg = (char *) v->Msgbuf;
  1890.                   ++v->xpru.xpru_errors;
  1891.                   display_update(&v->xpru);
  1892.                   zmputs(v, v->Attn);
  1893.                   continue;
  1894.                 case TIMEOUT:
  1895.                   if (--n < 0)
  1896.                     return ZM_ERROR;
  1897.                   v->xpru.xpru_updatemask = XPRU_ERRORMSG | XPRU_TIMEOUTS;
  1898.                   sprintf(find_end(v->Msgbuf), "MSG_AT %ld RETRIES %ld LEFT",
  1899.                             v->Rxbytes, (long) n);
  1900.                   v->xpru.xpru_errormsg = (char *) v->Msgbuf;
  1901.                   ++v->xpru.xpru_timeouts;
  1902.                   display_update(&v->xpru);
  1903.                   continue;
  1904.                 case GOTCRCW:   /*
  1905.                                  * Sender says it's waiting for an ACK
  1906.                                  */
  1907.                   n = v->ErrorLimit;
  1908.                   if (putsec(v) == ZM_ERROR)
  1909.                     return ZM_ERROR;
  1910.                   stohdr(v, v->Rxbytes);
  1911.                   zshhdr(v, ZACK);
  1912.                   sendbuf(v);
  1913.                   goto nxthdr;
  1914.                 case GOTCRCQ:   /*
  1915.                                  * Sender says it's not waiting,
  1916.                                  */
  1917.              /*
  1918.               * but ACK anyway (rarely used)
  1919.               */
  1920.                   n = v->ErrorLimit;
  1921.                   if (putsec(v) == ZM_ERROR)
  1922.                     return ZM_ERROR;
  1923.                   stohdr(v, v->Rxbytes);
  1924.                   zshhdr(v, ZACK);
  1925.                   sendbuf(v);
  1926.                   goto moredata;
  1927.                 case GOTCRCG:   /*
  1928.                                  * Sender says keep receiving, there's more
  1929.                                  * coming
  1930.                                  */
  1931.                   n = v->ErrorLimit;
  1932.                   if (putsec(v) == ZM_ERROR)
  1933.                     return ZM_ERROR;
  1934.                   goto moredata;
  1935.                 case GOTCRCE:   /*
  1936.                                  * Sender says this is the last packet
  1937.                                  */
  1938.                   n = v->ErrorLimit;
  1939.                   if (putsec(v) == ZM_ERROR)
  1940.                     return ZM_ERROR;
  1941.                   goto nxthdr;
  1942.               }
  1943.         }
  1944.     }
  1945. }       /*
  1946.          * End of short rzfile()
  1947.          */
  1948.  
  1949. /************************ZM_**********************************
  1950.  *      short procheader(struct Vars *v)
  1951.  *
  1952.  * Process file name & info packet; either open file and
  1953.  * prepare to receive, or return ZM_ERROR if we should skip
  1954.  * this one for some reason
  1955.  **********************************************************/
  1956. short
  1957. procheader(struct Vars *v)
  1958. {
  1959.   struct SetupVars *sv;
  1960.   UBYTE    *p,
  1961.            *openmode,
  1962.             buff[PATHLEN];
  1963.   long      n;
  1964.  
  1965.   openmode = "w";
  1966.   v->Strtpos = 0;
  1967.  
  1968. /*
  1969.  * Extract expected filesize from file info packet, if given
  1970.  */
  1971.   v->Fsize = -1;
  1972.   p = find_end(v->Pktbuf) + 1;
  1973.  
  1974.   if (*p)
  1975.     {
  1976.       char     *index,
  1977.                *ptr;
  1978.  
  1979.       index = skip_chars(ptr = p);
  1980.  
  1981.       v->Fsize = atol(ptr);
  1982.  
  1983.       index = skip_chars(ptr = index);
  1984.  
  1985.       v->Modtime = from_octal(ptr);
  1986.  
  1987.       skip_chars(ptr = index);
  1988.  
  1989.       v->Bits = from_octal(ptr);
  1990.  
  1991.       v->SetAttributes = TRUE;
  1992.     }
  1993.   else
  1994.     {
  1995.       v->Modtime = 0;
  1996.       v->Bits = 0;
  1997.       v->SetAttributes = FALSE;
  1998.     }
  1999.  
  2000. /*
  2001.  * If option RY set, use full received file path
  2002.  */
  2003.   sv = (void *) v->io.xpr_data;
  2004.   if (*sv->option_r == 'Y')
  2005.     strcpy(v->Filename, v->Pktbuf);
  2006.   else
  2007.     {
  2008.  /*
  2009.   * else use the default directory path specified in the setup options
  2010.   */
  2011.       strcpy(v->Filename, sv->option_p);
  2012.       p = v->Filename + strlen(v->Filename) - 1;
  2013.       if (p >= v->Filename && *p != '/' && *p != ':')
  2014.         *++p = '/';
  2015.       *++p = '\0';
  2016.  /*
  2017.   * Append the filename from the file info packet; ignore anything before *
  2018.   * last /, \, or : in filename (received directory path is ignored)
  2019.   */
  2020.       p = find_end(v->Pktbuf);  /*
  2021.                                  * start at end and scan back
  2022.                                  */
  2023.  /*
  2024.   * to start of name
  2025.   */
  2026.       while (p >= v->Pktbuf && *p != '/' && *p != '\\' && *p != ':')
  2027.         --p;
  2028.       strcat(v->Filename, ++p);
  2029.     }
  2030.  
  2031. /*
  2032.  * Make sure we have room for file; skip it if not.
  2033.  */
  2034.  
  2035.   if (v->Fsize > getfree(v))
  2036.     {
  2037.       sprintf(v->Msgbuf, "MSG_INSUFFICIENT_DISK_SPACE Size:%ld Avail:%ld",
  2038.                 v->Fsize, getfree(v));
  2039.       upderr(v, v->Msgbuf);
  2040.       v->Noroom = TRUE;
  2041.       return ZM_ERROR;
  2042.     }
  2043.  
  2044. /*
  2045.  * Display name of file being received for user
  2046.  */
  2047.   v->xpru.xpru_updatemask = XPRU_FILENAME;
  2048.   v->xpru.xpru_filename = (char *) v->Filename;
  2049.   display_update(&v->xpru);
  2050.  
  2051. /*
  2052.  * If a file with this name already exists, handle in * accordance with O
  2053.  * option
  2054.  */
  2055.   if (exist(v))
  2056.     {
  2057.       switch (*sv->option_o)
  2058.         {
  2059.           case 'N':     /*
  2060.                          * Don't overwrite; change name to prevent collision
  2061.                          */
  2062.             strcpy(buff, v->Filename);
  2063.             strcat(v->Filename, ".dup");
  2064.             n = 2;
  2065.             while (exist(v))
  2066.               {
  2067.                 sprintf(v->Filename, "%s.dup%ld", buff, n);
  2068.                 ++n;
  2069.               }
  2070.        /*
  2071.         * Update filename display to show new name
  2072.         */
  2073.             display_update(&v->xpru);
  2074.             break;
  2075.           case 'R':     /*
  2076.                          * Resume transfer from current end of file
  2077.                          */
  2078.             openmode = "a";
  2079.             v->Strtpos = xpr_finfo(v->Filename, 1L);
  2080.             break;
  2081.           case 'S':     /*
  2082.                          * Skip it
  2083.                          */
  2084.             upderr(v, "MSG_FILE_ALREADY_EXISTS");
  2085.             return ZM_ERROR;
  2086.        /*
  2087.         * Else 'Y', go ahead and overwrite it (openmode = w)
  2088.         */
  2089.         }
  2090.     }
  2091.  
  2092. /*
  2093.  * Set text/binary mode according to options before opening file
  2094.  */
  2095.   set_textmode(v);
  2096.  
  2097. /*
  2098.  * Figure out file translation mode to use; either binary (verbatim *
  2099.  * transfer) or ASCII (perform end-of-line conversions).  If user has *
  2100.  * specified a mode (TY or TN), that's what we use.  If user says use *
  2101.  * sender's suggestion (T?), set mode according to Zconv flag.  If neither *
  2102.  * side specifies, default to binary mode.
  2103.  */
  2104.   v->Thisbinary = v->Rxbinary || !v->Rxascii;
  2105.   if (!v->Rxbinary && v->Zconv == ZCNL)
  2106.     v->Thisbinary = FALSE;
  2107.   if (!v->Rxascii && v->Zconv == ZCBIN)
  2108.     v->Thisbinary = TRUE;
  2109.  
  2110. /*
  2111.  * Open the file (finally)
  2112.  */
  2113.   if (!(v->File = bfopen(v, openmode)))
  2114.     {
  2115.       ++v->Errcnt;
  2116.       upderr(v, "MSG_CANT_OPEN_FILE");
  2117.       return ZM_ERROR;
  2118.     }
  2119.   GetSysTime(&v->Starttime);
  2120.   v->BytesReceived = 0;
  2121.  
  2122. /*
  2123.  * Initialize comm program transfer status display
  2124.  */
  2125.   v->xpru.xpru_updatemask = XPRU_PROTOCOL | XPRU_FILESIZE | XPRU_MSG
  2126.     | XPRU_BLOCKS | XPRU_ERRORS | XPRU_TIMEOUTS | XPRU_BLOCKCHECK
  2127.     | XPRU_BYTES | XPRU_ELAPSEDTIME;
  2128.   v->xpru.xpru_protocol = "ZModem";
  2129.   v->xpru.xpru_filesize = v->Fsize;
  2130.   v->xpru.xpru_msg = (v->Thisbinary) ? "MSG_RECEIVING_BINARY_FILE"
  2131.     : "MSG_RECEIVING_TEXT_FILE";
  2132.   v->xpru.xpru_blocks = v->xpru.xpru_errors = v->xpru.xpru_timeouts = 0;
  2133.   v->xpru.xpru_blockcheck = v->Crc32 ? "CRC-32" : "CRC-16";
  2134.   v->xpru.xpru_bytes = v->Strtpos;
  2135.   v->xpru.xpru_blocksize = v->ksize;
  2136.   update_rate(v);
  2137.   display_update(&v->xpru);
  2138.  
  2139.   return OK;
  2140. }       /*
  2141.          * End of short procheader()
  2142.          */
  2143.  
  2144. /**********************************************************
  2145.  *      short putsec(struct Vars *v)
  2146.  *
  2147.  * Writes the received file data to the output file.
  2148.  * If in ASCII mode, stops writing at first ^Z, and converts all
  2149.  * \r\n pairs or solo \r's to \n's.
  2150.  **********************************************************/
  2151. short
  2152. putsec(struct Vars *v)
  2153. {
  2154.   char      nl = '\n';
  2155.   UBYTE    *p;
  2156.   short     n;
  2157.  
  2158. /*
  2159.  * If in binary mode, write it out verbatim
  2160.  */
  2161.   if (v->Thisbinary)
  2162.     {
  2163.       if (bfwrite(v, v->Pktbuf, (long) v->Rxcount) != v->Rxcount)
  2164.         goto diskfull;
  2165.  /*
  2166.   * If in text mode, perform end-of-line cleanup
  2167.   */
  2168.     }
  2169.   else
  2170.     {
  2171.       if (v->Eofseen)
  2172.         return OK;
  2173.       for (p = v->Pktbuf, n = v->Rxcount; --n >= 0; ++p)
  2174.         {
  2175.           if (*p == ZM_CPMEOF)
  2176.             {
  2177.               v->Eofseen = TRUE;
  2178.               return OK;
  2179.             }
  2180.           else if (*p != '\n' && v->Lastsent == '\r')
  2181.             {
  2182.               if (bfwrite(v, &nl, 1L) != 1)
  2183.                 goto diskfull;
  2184.             }
  2185.           if (*p != '\r' && bfwrite(v, p, 1L) != 1)
  2186.             goto diskfull;
  2187.           v->Lastsent = *p;
  2188.         }
  2189.     }
  2190.  
  2191. /*
  2192.  * Update comm program status display
  2193.  */
  2194.   v->xpru.xpru_updatemask = XPRU_BLOCKS | XPRU_BLOCKSIZE | XPRU_BYTES
  2195.     | XPRU_ELAPSEDTIME | XPRU_BLOCKCHECK;
  2196.   ++v->xpru.xpru_blocks;
  2197.   v->xpru.xpru_blocksize = v->Rxcount;
  2198.   v->xpru.xpru_bytes = v->Rxbytes += v->Rxcount;
  2199.   v->xpru.xpru_blockcheck = v->Crc32 ? "CRC-32" : "CRC-16";
  2200.   update_rate(v);
  2201.   display_update(&v->xpru);
  2202.  
  2203.   return OK;
  2204.  
  2205. diskfull:
  2206.   upderr(v, "MSG_ERROR_WRITING_FILE");
  2207.   v->Noroom = TRUE;
  2208.   return ZM_ERROR;
  2209. }       /*
  2210.          * End of short putsec()
  2211.          */
  2212.  
  2213. /**********************************************************
  2214.  *      void ackbibi(struct Vars *v)
  2215.  *
  2216.  * End of batch transmission; disengage cleanly from sender
  2217.  **********************************************************/
  2218. void
  2219. ackbibi(struct Vars *v)
  2220. {
  2221.   short     n;
  2222.  
  2223.   stohdr(v, 0L);
  2224.   for (n = 4; --n;)
  2225.     {
  2226.       zshhdr(v, ZFIN);
  2227.       sendbuf(v);
  2228.       switch (readock(v, 100))
  2229.         {
  2230.           case 'O':
  2231.             readock(v, 1);      /*
  2232.                                  * Discard 2nd 'O'
  2233.                                  */
  2234.           case TIMEOUT:
  2235.           case RCDO:
  2236.             return;
  2237.         }
  2238.     }
  2239. }       /*
  2240.          * End of void ackbibi()
  2241.          */
  2242. /*
  2243.  * End of Receive.c source
  2244.  */
  2245. /**********************************************************************
  2246.  * Send.c: File transmission routines for xprzmodem.library;
  2247.  * Original Version 2.10, 12 February 1991, by Rick Huebner.
  2248.  * Based closely on Chuck Forsberg's sz.c example ZModem code,
  2249.  * but too pervasively modified to even think of detailing the changes.
  2250.  * Released to the Public Domain; do as you like with this code.
  2251.  *
  2252.  * Version 2.50, 15 November 1991, CRC-32 additions by William M. Perkins.
  2253.  * Version 2.51 29, January 1992, RX_timout fix by John Tillema
  2254.  * Version 2.52   6 March 1992, Very minor fix with compiled 020 library
  2255.  *               by William M. Perkins.
  2256.  * Version 2.53, 28 June 1993, several additions by Olaf `Olsen' Barthel
  2257.  **********************************************************************/
  2258.  
  2259. /*
  2260.  * Convert decimal to octal value.
  2261.  */
  2262. VOID
  2263. to_octal(STRPTR buf, ULONG value)
  2264. {
  2265.   UBYTE     buffer[20];
  2266.   short     i = 1;
  2267.  
  2268.   while (value)
  2269.     {
  2270.       buffer[i++] = '0' + (value & 7);
  2271.  
  2272.       value >>= 3;
  2273.     }
  2274.  
  2275.   do
  2276.     *buf++ = buffer[--i];
  2277.   while (i);
  2278.  
  2279.   *buf = 0;
  2280. }
  2281.  
  2282. /**********************************************************
  2283.  *      long XProtocolSend(struct XPR_IO *xio)
  2284.  *
  2285.  * Main file transmission routine; called by comm program
  2286.  **********************************************************/
  2287. long
  2288. XProtocolSend(struct XPR_IO *xio)
  2289. {
  2290.   struct Vars *v;
  2291.   short     err;
  2292.  
  2293. /*
  2294.  * Perform common setup and initializations
  2295.  */
  2296.   if (!(v = setup(xio)))
  2297.     return XPRS_FAILURE;
  2298.  
  2299. /*
  2300.  * was 600, set to 300 to fix so it uploads correctly
  2301.  */
  2302.   v->Rxtimeout = 300;
  2303.   v->Wantfcs32 = TRUE;
  2304.   v->Rxflags = 0;
  2305.   v->Receiving = FALSE;
  2306.  
  2307. /*
  2308.  * Transfer the files
  2309.  */
  2310.   zmputs(v, "rz\r");
  2311.   stohdr(v, 0L);
  2312.   zshhdr(v, ZRQINIT);
  2313.   sendbuf(v);
  2314.   if (getzrxinit(v) == ZM_ERROR)
  2315.     upderr(v, "MSG_UPLOAD_CANCELED_TXT");
  2316.   else
  2317.     sendbatch(v);
  2318.  
  2319. /*
  2320.  * Clean up and return
  2321.  */
  2322.   if (err = v->Errcnt)
  2323.     upderr(v, "MSG_FILES_SKIPPED_DUE_TO_ERRORS_TXT");
  2324.   else
  2325.     updmsg(v, "MSG_DONE_TXT");
  2326.   FreeMem(v->Filebuf, v->Filebufmax);
  2327.   FreeMem(v, (long) sizeof(struct Vars));
  2328.  
  2329.   return (err) ? XPRS_FAILURE : XPRS_SUCCESS;
  2330. }       /*
  2331.          * End of long XProtocolSend()
  2332.          */
  2333.  
  2334. /**********************************************************
  2335.  *      short getzrxinit(struct Vars *v)
  2336.  *
  2337.  * Negotiate with receiver to start a file transfer
  2338.  **********************************************************/
  2339. short
  2340. getzrxinit(struct Vars *v)
  2341. {
  2342.   short     n;
  2343.  
  2344.   for (n = v->ErrorLimit; --n >= 0;)
  2345.     {
  2346.  /*
  2347.   * Check for abort from comm program
  2348.   */
  2349.       if ( xpr_chkabort() )
  2350.         {
  2351.           canit(v);     /*
  2352.                          * Receiver does not respond to ZABORT.
  2353.                          */
  2354.           return ZM_ERROR;
  2355.         }
  2356.       switch (zgethdr(v))
  2357.         {
  2358.           case ZCHALLENGE:      /*
  2359.                                  * Echo receiver's challenge number
  2360.                                  */
  2361.             stohdr(v, v->Rxpos);
  2362.             zshhdr(v, ZACK);
  2363.             sendbuf(v);
  2364.             continue;
  2365.           case ZCOMMAND:        /*
  2366.                                  * They didn't see our ZRQINIT; try again
  2367.                                  */
  2368.             stohdr(v, 0L);
  2369.             zshhdr(v, ZRQINIT);
  2370.             sendbuf(v);
  2371.             continue;
  2372.           case ZRINIT:          /*
  2373.                                  * Receiver ready; get transfer parameters
  2374.                                  */
  2375.             v->Rxflags = 0xFF & v->Rxhdr[ZF0];
  2376.             v->Txfcs32 = (v->Wantfcs32 && (v->Rxflags & CANFC32));
  2377.             v->Zctlesc |= v->Rxflags & TESCCTL;
  2378.             v->Rxbuflen = ((USHORT) v->Rxhdr[ZP1] << 8) | v->Rxhdr[ZP0];
  2379.        /*
  2380.         * Use shortest of the two side's max frame lengths
  2381.         */
  2382.             if (v->Tframlen && (!v->Rxbuflen || v->Tframlen < v->Rxbuflen))
  2383.               v->Rxbuflen = v->Tframlen;
  2384.             return (sendzsinit(v));
  2385.           case ZCAN:
  2386.           case RCDO:
  2387.           case TIMEOUT:
  2388.             upderr(v, v->Msgbuf);
  2389.             return ZM_ERROR;
  2390.           case ZRQINIT:
  2391.             if (v->Rxhdr[ZF0] == ZCOMMAND)
  2392.               continue;
  2393.        /*
  2394.         * fallthrough...
  2395.         */
  2396.           default:
  2397.             zshhdr(v, ZNAK);
  2398.             sendbuf(v);
  2399.             continue;
  2400.         }
  2401.     }
  2402.   return ZM_ERROR;
  2403. }       /*
  2404.          * End of short getzrxinit()
  2405.          */
  2406.  
  2407. /*
  2408.  * Send send-init information
  2409.  */
  2410. short
  2411. sendzsinit(struct Vars *v)
  2412. {
  2413.   if (v->Attn[0] == '\0' && (!v->Zctlesc || (v->Rxflags & TESCCTL)))
  2414.     return OK;
  2415.   else
  2416.     {
  2417.       short     c,
  2418.                 errors = 0;
  2419.  
  2420.       for (;;)
  2421.         {
  2422.           stohdr(v, 0L);
  2423.           if (v->Zctlesc)
  2424.             {
  2425.               v->Txhdr[ZF0] |= TESCCTL;
  2426.               zshhdr(v, ZSINIT);
  2427.             }
  2428.           else
  2429.             zsbhdr(v, ZSINIT);
  2430.  
  2431.           v->Outbuf[0] = 0;
  2432.           zsdata(v, 1, ZCRCW);
  2433.  
  2434.           c = zgethdr(v);
  2435.           switch (c)
  2436.             {
  2437.               case ZCAN:
  2438.                 return ZM_ERROR;
  2439.               case ZACK:
  2440.                 return OK;
  2441.               default:
  2442.                 if (++errors > v->ErrorLimit)
  2443.                   return ZM_ERROR;
  2444.                 continue;
  2445.             }
  2446.         }
  2447.     }
  2448. }       /*
  2449.          * End of short sendzsinit()
  2450.          */
  2451.  
  2452. /**********************************************************
  2453.  *      void sendbatch(struct Vars *v)
  2454.  *
  2455.  * Send a batch of files
  2456.  **********************************************************/
  2457. void
  2458. sendbatch(struct Vars *v)
  2459. {
  2460.   UBYTE     single,
  2461.             done = FALSE;
  2462.   long      fstate;
  2463.  
  2464.       single = FALSE;
  2465.       fstate = xpr_ffirst(v->Filename, v->io.xpr_filename);
  2466.       if (!fstate)
  2467.         {
  2468.           upderr(v, "MSG_NO_FILES_MATCH_TEMPLATE_TXT");
  2469.           return;
  2470.         }
  2471.  
  2472. /*
  2473.  * If using templates, keep getting names & sending until done
  2474.  */
  2475.   while (!done)
  2476.     {
  2477.       if (sendone(v) == ZM_ERROR)
  2478.         return;
  2479.       if (single)
  2480.         break;
  2481.       fstate = xpr_fnext(fstate, v->Filename, v->io.xpr_filename);
  2482.       done = !fstate;
  2483.     }
  2484.  
  2485. /*
  2486.  * End batch and return; if we never got started, just cancel receiver
  2487.  */
  2488.   if (v->Filcnt)
  2489.     saybibi(v);
  2490.   else
  2491.     canit(v);
  2492. }       /*
  2493.          * End of void sendbatch()
  2494.          */
  2495.  
  2496. /**********************************************************
  2497.  *      short sendone(struct Vars *v)
  2498.  *
  2499.  * Send the file named in v->Filename
  2500.  **********************************************************/
  2501. short
  2502. sendone(struct Vars *v)
  2503. {
  2504.   struct SetupVars *sv;
  2505.  
  2506. /*
  2507.  * Display name of file being sent for user
  2508.  */
  2509.   v->xpru.xpru_updatemask = XPRU_FILENAME;
  2510.   v->xpru.xpru_filename = v->Filename;
  2511.   display_update(&v->xpru);
  2512.  
  2513. /*
  2514.  * Set text/binary mode according to options before opening file
  2515.  */
  2516.   set_textmode(v);
  2517.  
  2518. /*
  2519.  * Open the file, if possible
  2520.  */
  2521.   if (!(v->File = bfopen(v, "r")))
  2522.     {
  2523.       ++v->Errcnt;
  2524.       upderr(v, "MSG_CANT_OPEN_FILE_TXT");
  2525.       return OK;        /*
  2526.                          * pass over it, there may be others
  2527.                          */
  2528.     }
  2529.   ++v->Filcnt;
  2530.   GetSysTime(&v->Starttime);
  2531.   v->BytesSent = 0;
  2532.  
  2533. /*
  2534.  * Kick off the file transfer
  2535.  */
  2536.   sv = (void *) v->io.xpr_data;
  2537.   switch (sendname(v))
  2538.     {
  2539.       case ZM_ERROR:
  2540.         ++v->Errcnt;
  2541.         return ZM_ERROR;
  2542.       case OK:
  2543.         bfclose(v);
  2544.    /*
  2545.     * File sent; if option DY, delete file after sending
  2546.     */
  2547.         if (*sv->option_d == 'Y' )
  2548.           {
  2549.             updmsg(v, "MSG_DELETING_FILE_AFTER_SEND_TXT");
  2550.             unlink(v->Filename);
  2551.           }
  2552.         break;
  2553.     }
  2554.   return OK;
  2555. }       /*
  2556.          * End of short sendone()
  2557.          */
  2558.  
  2559. /**********************************************************
  2560.  *      short sendname(struct Vars *v)
  2561.  *
  2562.  * Build file info block consisting of file name, length,
  2563.  * time, and mode
  2564.  **********************************************************/
  2565. short
  2566. sendname(struct Vars *v)
  2567. {
  2568.   struct SetupVars *sv;
  2569.   UBYTE    *p,
  2570.            *q,
  2571.             buff[32],
  2572.             mode[5];
  2573.   BPTR      FileLock;
  2574.  
  2575. /*
  2576.  * Initialize comm program transfer status display
  2577.  */
  2578.   v->Fsize = xpr_finfo(v->Filename, 1L);
  2579.   v->xpru.xpru_updatemask = XPRU_PROTOCOL | XPRU_FILESIZE | XPRU_MSG
  2580.     | XPRU_BLOCKS | XPRU_ERRORS | XPRU_TIMEOUTS | XPRU_BLOCKCHECK
  2581.     | XPRU_BYTES | XPRU_ELAPSEDTIME;
  2582.   v->xpru.xpru_protocol = "ZModem";
  2583.   v->xpru.xpru_filesize = v->Fsize;
  2584.   v->xpru.xpru_msg = (v->Lzconv == ZCNL) ? "MSG_SENDING_TEXT_FILE_TXT" :
  2585.     ((v->Lzconv == ZCBIN) ? "MSG_SENDING_BINARY_FILE_TXT" : "MSG_SENDING_FILE_TXT");
  2586.   v->xpru.xpru_blocks = v->xpru.xpru_errors = v->xpru.xpru_timeouts = 0;
  2587.   v->xpru.xpru_blockcheck = v->Crc32t ? "CRC-32" : "CRC-16";
  2588.   v->xpru.xpru_bytes = v->Strtpos = 0;
  2589.   v->xpru.xpru_blocksize = v->ksize;
  2590.   update_rate(v);
  2591.   display_update(&v->xpru);
  2592.  
  2593.   sv = (void *) v->io.xpr_data;
  2594.   if (*sv->option_s == 'Y')
  2595.     {
  2596.  /*
  2597.   * If "SY" option selected, send full path
  2598.   */
  2599.       strcpy(v->Pktbuf, v->Filename);
  2600.       p = v->Pktbuf + strlen(v->Pktbuf) + 1;
  2601.     }
  2602.   else
  2603.     {
  2604.  /*
  2605.   * else extract outgoing file name without directory path
  2606.   */
  2607.       for (p = v->Filename, q = v->Pktbuf; *p; ++p, ++q)
  2608.         if ((*q = *p) == '/' || *q == ':')
  2609.           q = v->Pktbuf - 1;
  2610.       *q = '\0';
  2611.       p = ++q;
  2612.     }
  2613.  
  2614. /*
  2615.  * Zero out remainder of file info packet
  2616.  */
  2617.   memset(p, 0, sizeof(v->Pktbuf) - (p - v->Pktbuf));
  2618.  
  2619. /*
  2620.  * Store file size, timestamp, and mode in info packet
  2621.  */
  2622.   if (v->FileAttributes & 1)
  2623.     {
  2624.       ULONG     Seconds = getsystime(NULL),
  2625.                 Mode = 0000;      /*
  2626.  
  2627.                                    * owner = rwx, group = rwx, others = rwx
  2628.                                    */
  2629.  
  2630.  /*
  2631.   * See if we can lock it, this probably won't work for `term'.
  2632.   */
  2633.       if (FileLock = Lock(v->Filename, ACCESS_READ))
  2634.         {
  2635.           struct FileInfoBlock __aligned FileInfo;
  2636.  
  2637.      /*
  2638.       * Any info available?
  2639.       */
  2640.           if (Examine(FileLock, &FileInfo))
  2641.             {
  2642.          /*
  2643.           * Modification date.
  2644.           */
  2645.               Seconds = (  FileInfo.fib_Date.ds_Days * 24 * 60
  2646.                         +  FileInfo.fib_Date.ds_Minute) * 60
  2647.                         + (FileInfo.fib_Date.ds_Tick) / TICKS_PER_SECOND;
  2648.  
  2649.          /*
  2650.           * Take care of the owner bits.
  2651.           */
  2652.               if (FileInfo.fib_Protection & FIBF_EXECUTE)
  2653.                 Mode |= 0100;
  2654.  
  2655.               if (FileInfo.fib_Protection & (FIBF_WRITE | FIBF_DELETE))
  2656.                 Mode |= 0200;
  2657.  
  2658.               if (FileInfo.fib_Protection & FIBF_READ)
  2659.                 Mode |= 0400;
  2660.  
  2661.          /*
  2662.           * Take care of the group bits.
  2663.           */
  2664.               if (!(FileInfo.fib_Protection & FIBF_GRP_EXECUTE))
  2665.                 Mode |= 0010;
  2666.  
  2667.               if (!(FileInfo.fib_Protection & FIBF_GRP_WRITE) || !(FileInfo.fib_Protection & FIBF_GRP_DELETE))
  2668.                 Mode |= 0020;
  2669.  
  2670.               if (!(FileInfo.fib_Protection & FIBF_GRP_READ))
  2671.                 Mode |= 0040;
  2672.  
  2673.          /*
  2674.           * Take care of the other bits.
  2675.           */
  2676.               if (!(FileInfo.fib_Protection & FIBF_OTR_EXECUTE))
  2677.                 Mode |= 0001;
  2678.  
  2679.               if (!(FileInfo.fib_Protection & FIBF_OTR_WRITE) || !(FileInfo.fib_Protection & FIBF_OTR_DELETE))
  2680.                 Mode |= 0002;
  2681.  
  2682.               if (!(FileInfo.fib_Protection & FIBF_OTR_READ))
  2683.                 Mode |= 0004;
  2684.             }
  2685.  
  2686.           UnLock(FileLock);
  2687.         }
  2688.  
  2689.       to_octal(buff, Seconds);
  2690.       to_octal(mode, Mode);
  2691.     }
  2692.   else
  2693.     {
  2694.       to_octal(buff, getsystime(NULL));
  2695.       to_octal(mode, 0000);
  2696.     }
  2697.  
  2698. /*
  2699.  * amiga.lib mysprintf() can't do %lo format, so we do it the hard way
  2700.  */
  2701. /*
  2702.  * Yes, octal; ZModem was originally done on Unix, and they like octal there
  2703.  */
  2704.  
  2705.   sprintf(p, "%ld %s %s", (v->Fsize < 0) ? 0L : v->Fsize, buff, mode);
  2706.  
  2707. /*
  2708.  * Send filename packet
  2709.  */
  2710.   return zsendfile(v, (short) (p - v->Pktbuf + strlen(p) + 1));
  2711. }       /*
  2712.          * End of short sendname()
  2713.          */
  2714.  
  2715. /**********************************************************
  2716.  *      short zsendfile(struct Vars *v, short blen)
  2717.  *
  2718.  * Send the filename packet and see if receiver will accept
  2719.  * file
  2720.  **********************************************************/
  2721. short
  2722. zsendfile(struct Vars *v, short blen)
  2723. {
  2724.   short     c;
  2725.  
  2726.   while (TRUE)
  2727.     {
  2728.       v->Txhdr[ZF0] = v->Lzconv;        /*
  2729.                                          * Text or Binary mode; from config
  2730.                                          * string
  2731.                                          */
  2732.       v->Txhdr[ZF1] = LZMANAG;  /*
  2733.                                  * Default file management mode
  2734.                                  */
  2735.       v->Txhdr[ZF2] = LZTRANS;  /*
  2736.                                  * Default file transport mode
  2737.                                  */
  2738.       v->Txhdr[ZF3] = 0;
  2739.       zsbhdr(v, ZFILE);
  2740.       zsdata(v, blen, ZCRCW);
  2741.       sendbuf(v);
  2742.     again:
  2743.  /*
  2744.   * Check for abort from comm program
  2745.   */
  2746.       if ( xpr_chkabort() )
  2747.         {
  2748.           bfclose(v);
  2749.           canit(v);     /*
  2750.                          * Receiver does not respond to ZABORT.
  2751.                          */
  2752.           return ZM_ERROR;
  2753.         };
  2754.       switch (c = zgethdr(v))
  2755.         {
  2756.           case ZRINIT:
  2757.             goto again;
  2758.           case ZCAN:
  2759.           case ZCRC:
  2760.           case RCDO:
  2761.           case TIMEOUT:
  2762.           case ZABORT:
  2763.           case ZFIN:
  2764.             upderr(v, v->Msgbuf);
  2765.             return ZM_ERROR;
  2766.           case ZSKIP:   /*
  2767.                          * Receiver doesn't want this one
  2768.                          */
  2769.             upderr(v, "MSG_SKIP_COMMAND_RECEIVED_TXT");
  2770.             bfclose(v);
  2771.             return c;
  2772.           case ZRPOS:   /*
  2773.                          * Receiver wants it; this is starting position
  2774.                          */
  2775.             bfseek(v, v->Rxpos);
  2776.             v->Strtpos = v->Txpos = v->Rxpos;
  2777.             xpr_sflush();
  2778.             v->Modemcount = 0;
  2779.             return zsendfdata(v);
  2780.         }
  2781.     }
  2782. }       /*
  2783.          * End of short zsendfile()
  2784.          */
  2785.  
  2786. /**********************************************************
  2787.  *      short zsendfdata(struct Vars *v)
  2788.  *
  2789.  * Send the file data
  2790.  **********************************************************/
  2791. short
  2792. zsendfdata(struct Vars *v)
  2793. {
  2794.   short     c,
  2795.             e,
  2796.             blklen,
  2797.             goodbytes = 0;
  2798.   USHORT    framelen,
  2799.             maxblklen,
  2800.             goodneeded = 512;
  2801.  
  2802. /*
  2803.  * Figure out max data packet size to send
  2804.  */
  2805.   maxblklen = v->ksize;
  2806.   if (v->Rxbuflen && maxblklen > v->Rxbuflen)
  2807.     maxblklen = v->Rxbuflen;
  2808.   blklen = (v->Baud < 1200) ? 256 : v->ksize;
  2809.   if (blklen > maxblklen)
  2810.     blklen = maxblklen;
  2811.  
  2812. /*
  2813.  * If an interruption happened, handle it; else keep sending data
  2814.  */
  2815. somemore:
  2816.   while (char_avail(v))
  2817.     {
  2818.  /*
  2819.   * Check for another incoming packet while discarding line noise
  2820.   */
  2821.       switch (readock(v, 1))
  2822.         {
  2823.           case ZM_CAN:
  2824.           case RCDO:
  2825.           case ZPAD:
  2826.             break;
  2827.           default:
  2828.             continue;
  2829.         }
  2830.     waitack:
  2831.       switch (c = getinsync(v))
  2832.         {
  2833.           default:
  2834.             upderr(v, "MSG_TRANSFER_CANCELED_TXT");
  2835.             bfclose(v);
  2836.             return ZM_ERROR;
  2837.           case ZSKIP:   /*
  2838.                          * Receiver changed its mind and wants to skip the
  2839.                          * file
  2840.                          */
  2841.             bfclose(v);
  2842.             return c;
  2843.           case ZACK:    /*
  2844.                          * ACK at end of frame; resume sending data
  2845.                          */
  2846.             break;
  2847.           case ZRPOS:   /*
  2848.                          * An error; resend data from last good point
  2849.                          */
  2850.             blklen >>= 2;
  2851.             if (blklen < MINBLOCK)
  2852.               blklen = MINBLOCK;
  2853.             if (goodneeded < MAXGOODNEEDED)
  2854.               goodneeded <<= 1;
  2855.             v->xpru.xpru_updatemask = XPRU_ERRORS;
  2856.             ++v->xpru.xpru_errors;
  2857.             display_update (&v->xpru);
  2858.             break;
  2859.           case ZRINIT:
  2860.             updmsg(v, "MSG_DONE_TXT");
  2861.             return OK;
  2862.         }
  2863.     }
  2864.  
  2865. /*
  2866.  * Transmit ZDATA frame header
  2867.  */
  2868.   framelen = v->Rxbuflen;
  2869.   stohdr(v, v->Txpos);
  2870.   zsbhdr(v, ZDATA);
  2871.  
  2872. /*
  2873.  * Keep sending data packets until finished or interrupted
  2874.  */
  2875.   do
  2876.     {
  2877.  /*
  2878.   * Read next chunk of file data
  2879.   */
  2880.       c = bfread(v, v->Pktbuf, (long) blklen);
  2881.  
  2882.  /*
  2883.   * Figure out how to handle this data packet
  2884.   */
  2885.       if (c < blklen)
  2886.         e = ZCRCE;      /*
  2887.                          * If end of file, this is last data packet
  2888.                          */
  2889.       else if (v->Rxbuflen && (framelen -= c) <= 0)
  2890.         e = ZCRCW;      /*
  2891.                          * If end of frame, ask for ACK
  2892.                          */
  2893.       else
  2894.         e = ZCRCG;      /*
  2895.                          * Else tell receiver to expect more data packets
  2896.                          */
  2897.  
  2898.       zsdata(v, c, e);  /*
  2899.                          * Send the packet
  2900.                          */
  2901.       sendbuf(v);
  2902.  
  2903.  /*
  2904.   * Update comm program status display
  2905.   */
  2906.       v->xpru.xpru_updatemask = XPRU_BLOCKS | XPRU_BLOCKSIZE | XPRU_BYTES
  2907.         | XPRU_ELAPSEDTIME | XPRU_BLOCKCHECK;
  2908.       ++v->xpru.xpru_blocks;
  2909.       v->xpru.xpru_blocksize = c;
  2910.       v->xpru.xpru_blockcheck = v->Crc32t ? "CRC-32" : "CRC-16";
  2911.       v->xpru.xpru_bytes = v->Txpos += c;
  2912.       update_rate(v);
  2913.       display_update(&v->xpru);
  2914.  
  2915.  /*
  2916.   * If we've been sending smaller than normal packets, see if it's * time to
  2917.   * bump the packet size up a notch yet
  2918.   */
  2919.       if (blklen < maxblklen && (goodbytes += c) >= goodneeded)
  2920.         {
  2921.           blklen <<= 1;
  2922.           if (blklen > maxblklen)
  2923.             blklen = maxblklen;
  2924.           goodbytes = 0;
  2925.         }
  2926.  /*
  2927.   * Check for abort from comm program
  2928.   */
  2929.           if( xpr_chkabort() )
  2930.             {
  2931.               canit(v);         /*
  2932.                                  * Receiver does not respond to ZABORT.
  2933.                                  */
  2934.               upderr(v, "MSG_TRANSFER_CANCELED_TXT");
  2935.               bfclose(v);
  2936.               return ZM_ERROR;
  2937.             }
  2938.  /*
  2939.   * If this was last packet in frame, go wait for ACK from receiver
  2940.   */
  2941.       if (e == ZCRCW)
  2942.         goto waitack;
  2943.  
  2944.  /*
  2945.   * * Check if receiver trying to interrupt us; look for incoming packet *
  2946.   * while discarding line noise
  2947.   */
  2948.       while (char_avail(v))
  2949.         {
  2950.           switch (readock(v, 1))
  2951.             {
  2952.               case ZM_CAN:
  2953.               case RCDO:
  2954.               case ZPAD:
  2955.            /*
  2956.             * Interruption detected; stop sending and process complaint
  2957.             */
  2958.                 zsdata(v, 0, ZCRCE);
  2959.                 sendbuf(v);
  2960.                 goto waitack;
  2961.             }
  2962.         }
  2963.     }
  2964.   while (e == ZCRCG);   /*
  2965.                          * If no interruption, keep sending data packets
  2966.                          */
  2967.  
  2968. /*
  2969.  * Done sending file data; send EOF and wait for receiver to acknowledge
  2970.  */
  2971.   while (TRUE)
  2972.     {
  2973.       updmsg(v, "MSG_SENDING_EOF_TXT");
  2974.       stohdr(v, v->Txpos);
  2975.       zsbhdr(v, ZEOF);
  2976.       sendbuf(v);
  2977.       switch (c = getinsync(v))
  2978.         {
  2979.           case ZACK:
  2980.             continue;
  2981.           case ZRPOS:
  2982.             goto somemore;
  2983.           case ZRINIT:
  2984.             updmsg(v, "MSG_EOF_ACKNOWLEDGED_TXT");
  2985.             update_rate(v);
  2986.             v->xpru.xpru_updatemask = XPRU_ELAPSEDTIME;
  2987.             display_update(&v->xpru);
  2988.             return OK;
  2989.           case ZSKIP:
  2990.             bfclose(v);
  2991.             return c;
  2992.           default:
  2993.             upderr(v, "MSG_TRANSFER_CANCELED_TXT");
  2994.             bfclose(v);
  2995.             return ZM_ERROR;
  2996.         }
  2997.     }
  2998. }       /*
  2999.          * End of short zsendfdata()
  3000.          */
  3001.  
  3002. /**********************************************************
  3003.  *      short getinsync(struct Vars *v)
  3004.  *
  3005.  * Respond to receiver's complaint, get back in sync with
  3006.  * receiver
  3007.  **********************************************************/
  3008. short
  3009. getinsync(struct Vars *v)
  3010. {
  3011.   short     c;
  3012.  
  3013.   while (TRUE)
  3014.     {
  3015.       c = zgethdr(v);
  3016.       xpr_sflush();
  3017.       v->Modemcount = 0;
  3018.       switch (c)
  3019.         {
  3020.           case ZCAN:
  3021.           case ZABORT:
  3022.           case ZFIN:
  3023.           case RCDO:
  3024.           case TIMEOUT:
  3025.             upderr(v, v->Msgbuf);
  3026.             return ZM_ERROR;
  3027.           case ZRPOS:
  3028.             bfseek(v, v->Rxpos);
  3029.             v->Txpos = v->Rxpos;
  3030.             sprintf(v->Msgbuf, "MSG_RESENDING_FROM %ld", v->Txpos);
  3031.             upderr(v, v->Msgbuf);
  3032.             return c;
  3033.           case ZSKIP:
  3034.             upderr(v, "MSG_SKIP_COMMAND_RECEIVED");
  3035.        /*
  3036.         * fallthrough...
  3037.         */
  3038.           case ZRINIT:
  3039.             bfclose(v);
  3040.        /*
  3041.         * fallthrough...
  3042.         */
  3043.           case ZACK:
  3044.             return c;
  3045.           default:
  3046.             zsbhdr(v, ZNAK);
  3047.             sendbuf(v);
  3048.             continue;
  3049.         }
  3050.     }
  3051. }       /*
  3052.          * End of short getinsync()
  3053.          */
  3054.  
  3055. /**********************************************************
  3056.  *      void saybibi(struct Vars *v)
  3057.  *
  3058.  * End of batch transmission; disengage cleanly from receiver
  3059.  **********************************************************/
  3060. void
  3061. saybibi(struct Vars *v)
  3062. {
  3063.   while (TRUE)
  3064.     {
  3065.       stohdr(v, 0L);
  3066.       zsbhdr(v, ZFIN);
  3067.       sendbuf(v);
  3068.       switch (zgethdr(v))
  3069.         {
  3070.           case ZFIN:
  3071.             sendline(v, 'O');
  3072.             sendline(v, 'O');
  3073.             sendbuf(v);
  3074.        /*
  3075.         * fallthrough...
  3076.         */
  3077.           case ZCAN:
  3078.           case RCDO:
  3079.           case TIMEOUT:
  3080.             return;
  3081.         }
  3082.     }
  3083. }       /*
  3084.          * End of void saybibi()
  3085.          */
  3086. /**********************************************************************
  3087.  * Utils.c: Miscellaneous support routines for xprzmodem.library;
  3088.  * Version 2.10, 12 February 1991, by Rick Huebner.
  3089.  * Released to the Public Domain; do as you like with this code.
  3090.  *
  3091.  * Version 2.50, 15 November 1991, by William M. Perkins.  Added code
  3092.  * to update_rate() function in utils.c to avoid the Guru # 80000005
  3093.  * you would have gotten if you had decided to adjust the system clock
  3094.  * back during an upload or download.
  3095.  *
  3096.  * Mysprintf() function to replace sprintf() and proto code to use
  3097.  * libinit.o and linent.o library code was supplied by Jim Cooper of SAS.
  3098.  *
  3099.  * Version 2.54, 28 June 1993, by Olaf `Olsen' Barthel. Got rid of the
  3100.  * timer.c code, added OS 2.0 dependencies, rewrote update_rate() to
  3101.  * display only the information which was really available, added
  3102.  * control-code escaping & run-length encoding, changed the abort
  3103.  * routine to pay attention to the different abort levels, removed
  3104.  * SAS/C library dependencies (octal conversion, etc.), added
  3105.  * support for proper file creation date and access permission bits.
  3106.  **********************************************************************/
  3107.  
  3108. /*
  3109.  * Transfer options to use if XProtocolSetup not called
  3110.  */
  3111. struct SetupVars Default_Config =
  3112. {
  3113.   NULL, NULL, 0,
  3114.   {"C"},
  3115.   {"N"},
  3116.   {"16"},
  3117.   {"0"},
  3118.   {"10"},
  3119.   {"N"},
  3120.   {"N"},
  3121.   {"N"},
  3122.   {"Y"},
  3123.   {"N"},
  3124.   {"Y"},
  3125.   {""},
  3126.   {"1024"},
  3127.   {"S"}
  3128. };
  3129.  
  3130. /*
  3131.  * Convert a string to all upper case characters.
  3132.  */
  3133. VOID
  3134. string_upper(STRPTR buf)
  3135. {
  3136.   UBYTE     c;
  3137.  
  3138.   while (c = *buf)
  3139.     *buf++ = ToUpper(c);
  3140. }
  3141.  
  3142. /*
  3143.  * Skip blanks in a string.
  3144.  */
  3145. STRPTR
  3146. skip_blank(STRPTR buf)
  3147. {
  3148.   UBYTE     c;
  3149.  
  3150.   while (c = *buf)
  3151.     {
  3152.       if (c == ' ' || c == ',' || c == '\t' || c == '\r' || c == '\n')
  3153.         buf++;
  3154.       else
  3155.         break;
  3156.     }
  3157.  
  3158.   return (buf);
  3159. }
  3160.  
  3161.  
  3162. /*
  3163.  * Get the local time, convert it to GMT.
  3164.  */
  3165. ULONG
  3166. getsystime(struct timeval *tv)
  3167. {
  3168.   struct timeval Now;
  3169.  
  3170.   GetSysTime(&Now);
  3171.   if (tv)
  3172.     {
  3173.       tv->tv_secs = Now.tv_secs;
  3174.       tv->tv_micro = 0;
  3175.     }
  3176.  
  3177.   return (Now.tv_secs);
  3178. }
  3179.  
  3180. /**********************************************************
  3181.  *      long XProtocolCleanup(struct XPR_IO *xio)
  3182.  *
  3183.  * Called by comm program to give us a chance to clean
  3184.  * up before program ends
  3185.  **********************************************************/
  3186. long
  3187. XProtocolCleanup(struct XPR_IO *xio)
  3188. {
  3189. /*
  3190.  * Release option memory, if any
  3191.  */
  3192.   if (xio->xpr_data)
  3193.     {
  3194.       FreeMem(xio->xpr_data, (long) sizeof(struct SetupVars));
  3195.  
  3196.       xio->xpr_data = NULL;
  3197.     }
  3198.  
  3199.   return XPRS_SUCCESS;
  3200. }       /*
  3201.          * End of long XProtocolCleanup()
  3202.          */
  3203. /**********************************************************
  3204.  *      struct Vars *setup(struct XPR_IO *io)
  3205.  *
  3206.  * Perform setup and initializations common to both Send
  3207.  * and Receive routines
  3208.  **********************************************************/
  3209. struct Vars *
  3210. setup(struct XPR_IO *io)
  3211. {
  3212.   extern long BaudTable[];
  3213.   struct SetupVars *sv;
  3214.   struct Vars *v;
  3215.   long      origbuf;
  3216. /*
  3217.  * Hook in default transfer options if XProtocolSetup wasn't called
  3218.  */
  3219.   if (!(sv = (void *) io->xpr_data))
  3220.     {
  3221.       io->xpr_data = AllocMem((long) sizeof(struct SetupVars), MEMF_PUBLIC | MEMF_CLEAR);
  3222.       if (!(sv = (void *) io->xpr_data))
  3223.         {
  3224.           ioerr(io, "MSG_NOT_ENOUGH_MEMORY_TXT");
  3225.           return NULL;
  3226.         }
  3227.       *sv = Default_Config;
  3228.     }
  3229.  
  3230. /*
  3231.  * Allocate memory for our unshared variables, to provide reentrancy
  3232.  */
  3233.   if (!(v = AllocMem((long) sizeof(struct Vars), MEMF_PUBLIC | MEMF_CLEAR)))
  3234.     {
  3235.     nomem:
  3236.       ioerr(io, "MSG_NOT_ENOUGH_MEMORY_TXT");
  3237.       return NULL;
  3238.     }
  3239.   v->Modemchar = v->Modembuf;
  3240.  
  3241. /*
  3242.  * * Allocate memory for our file I/O buffer; if we can't get as much as *
  3243.  * requested, keep asking for less until we hit minimum before giving up
  3244.  */
  3245.   v->Filebufmax = origbuf = atol(sv->option_b) * 1024;
  3246.   while (!(v->Filebuf = AllocMem(v->Filebufmax, 0L)))
  3247.     {
  3248.       if (v->Filebufmax > 1024)
  3249.         v->Filebufmax -= 1024;
  3250.       else
  3251.         {
  3252.           FreeMem(v, (long) sizeof(struct Vars));
  3253.  
  3254.           goto nomem;
  3255.         }
  3256.     }
  3257.  
  3258. /*
  3259.  * If framelength was intended to match buffer size, stay in sync
  3260.  */
  3261.   v->Tframlen = atol(sv->option_f);
  3262.   if (v->Tframlen && v->Tframlen == origbuf)
  3263.     v->Tframlen = v->Filebufmax;
  3264.  
  3265.   v->ErrorLimit = atol(sv->option_e);
  3266.  
  3267. /*
  3268.  * If selected, enable control character escape mode.
  3269.  */
  3270.   if (sv->option_c[0] == 'Y')
  3271.     v->Zctlesc = 1;
  3272.   else
  3273.     v->Zctlesc = 0;
  3274.  
  3275. /*
  3276.  * Take care of the file attribute options.
  3277.  */
  3278.   if (sv->option_i[0] == 'S')
  3279.     v->FileAttributes = 1;
  3280.   else
  3281.     {
  3282.       if (sv->option_i[0] == 'R')
  3283.         v->FileAttributes = 2;
  3284.       else
  3285.         v->FileAttributes = 3;
  3286.     }
  3287.  
  3288. /*
  3289.  * Get the maximum allowed packet size.
  3290.  */
  3291.   if ((v->ksize = atol(sv->option_m)) < MINBLOCK)
  3292.     v->ksize = MINBLOCK;
  3293.   else
  3294.     {
  3295.       if (v->ksize > KSIZE)
  3296.         v->ksize = KSIZE;
  3297.     }
  3298.  
  3299. /*
  3300.  * Copy caller's io struct into our Vars for easier passing
  3301.  */
  3302.   v->io   = *io;
  3303.   v->Baud = BaudTable[cfg.sysBaud];  /* set the current baud rate */
  3304.  
  3305.   return v;
  3306. }       /*
  3307.          * End of struct Vars *setup()
  3308.          */
  3309.  
  3310. /**********************************************************
  3311.  *      void set_textmode(struct Vars *v)
  3312.  *
  3313.  * Set text/binary mode flags in accordance with T option
  3314.  * setting
  3315.  **********************************************************/
  3316. void
  3317. set_textmode(struct Vars *v)
  3318. {
  3319.   struct SetupVars *sv;
  3320.   long      i;
  3321.  
  3322.   sv = (void *) v->io.xpr_data;
  3323.   switch (*sv->option_t)
  3324.     {
  3325.       case 'Y': /*
  3326.                          * Force text mode on receive; suggest text mode on
  3327.                          * send
  3328.                          */
  3329.       TY:
  3330.         v->Rxascii = TRUE;
  3331.         v->Rxbinary = FALSE;
  3332.         v->Lzconv = ZCNL;
  3333.         break;
  3334.       case 'N': /*
  3335.                          * Force binary mode on receive; suggest binary mode
  3336.                          * on send
  3337.                          */
  3338.       TN:
  3339.         v->Rxascii = FALSE;
  3340.         v->Rxbinary = TRUE;
  3341.         v->Lzconv = ZCBIN;
  3342.         break;
  3343.       case 'C': /*
  3344.                          * Ask comm program for proper mode for this file
  3345.                          */
  3346.             i = xpr_finfo(v->Filename, 2L);
  3347.             if (i == 1)         /*
  3348.                                  * Comm program says use binary mode
  3349.                                  */
  3350.               goto TN;
  3351.             if (i == 2)         /*
  3352.                                  * Comm program says use text mode
  3353.                                  */
  3354.               goto TY;
  3355.    /*
  3356.     * xpr_finfo() not provided (or failed); default to T?
  3357.     */
  3358.       case '?':
  3359.         v->Rxascii = v->Rxbinary = FALSE;
  3360.         v->Lzconv = 0;
  3361.         break;
  3362.     }
  3363. }       /*
  3364.          * End of void set_textmode()
  3365.          */
  3366.  
  3367. /**********************************************************
  3368.  *      UBYTE *find_option(UBYTE *buf, UBYTE option)
  3369.  *
  3370.  * Search for specified option setting in string
  3371.  **********************************************************/
  3372. UBYTE    *
  3373. find_option(UBYTE *buf, UBYTE option)
  3374. {
  3375.   while (*buf)
  3376.     {
  3377.       buf = skip_blank(buf);
  3378.  
  3379.       if (*buf == option)
  3380.         return ++buf;
  3381.  
  3382.       buf = skip_chars(buf);
  3383.     }
  3384.  
  3385.   return NULL;
  3386. }       /*
  3387.          * End of UBYTE *find_option()
  3388.          */
  3389.  
  3390. /**********************************************************
  3391.  *      void canit(struct Vars *v)
  3392.  *
  3393.  * send cancel string to get the other end to shut up
  3394.  **********************************************************/
  3395. void
  3396. canit(struct Vars *v)
  3397. {
  3398.   static char canistr[] =
  3399.   {24, 24, 24, 24, 24, 24, 24, 24, 24, 24,
  3400.    8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 0};
  3401.  
  3402.   zmputs(v, canistr);
  3403. }       /*
  3404.          * End of void canit()
  3405.          */
  3406.  
  3407. /**********************************************************
  3408.  *      void zmputs(struct Vars *v, UBYTE *s)
  3409.  *
  3410.  * Send a string to the modem, with processing for \336 (sleep 1 sec)
  3411.  * and \335 (break signal, ignored since XPR spec doesn't support it)
  3412.  **********************************************************/
  3413. void
  3414. zmputs(struct Vars *v, UBYTE *s)
  3415. {
  3416.   UBYTE     c;
  3417.  
  3418.   while (*s)
  3419.     {
  3420.       switch (c = *s++)
  3421.         {
  3422.           case '\336':
  3423.             Delay(TICKS_PER_SECOND);
  3424.           case '\335':
  3425.             break;
  3426.           default:
  3427.             sendline(v, c);
  3428.         }
  3429.     }
  3430.   sendbuf(v);
  3431. }       /*
  3432.          * End of void zmputs()
  3433.          */
  3434.  
  3435. /**********************************************************
  3436.  *      void xsendline(struct Vars *v, UBYTE c)
  3437.  *
  3438.  * Write one character to the modem
  3439.  **********************************************************/
  3440. void
  3441. xsendline(struct Vars *v, UBYTE c)
  3442. {
  3443.   v->Outbuf[v->Outbuflen++] = c;
  3444.   if (v->Outbuflen >= sizeof(v->Outbuf))
  3445.     sendbuf(v);
  3446. }       /*
  3447.          * End of void xsendline()
  3448.          */
  3449.  
  3450. /**********************************************************
  3451.  *      void sendbuf(struct Vars *v)
  3452.  *
  3453.  * Send any data waiting in modem output buffer
  3454.  **********************************************************/
  3455. void
  3456. sendbuf(struct Vars *v)
  3457. {
  3458.   if (v->Outbuflen)
  3459.     {
  3460.  /*
  3461.   * Do the bookkeeping.
  3462.   */
  3463.       v->BytesSent += v->Outbuflen;
  3464.       xpr_swrite(v->Outbuf, (long) v->Outbuflen);
  3465.       v->Outbuflen = 0;
  3466.     }
  3467. }       /*
  3468.          * End of void sendbuf()
  3469.          */
  3470.  
  3471. /**********************************************************
  3472.  *      short readock(struct Vars *v, short tenths)
  3473.  *
  3474.  * Get a byte from the modem;
  3475.  * return TIMEOUT if no read within timeout tenths of a
  3476.  * second, return RCDO if carrier lost or other fatal error
  3477.  * (sread returns -1).  Added in some buffering so we
  3478.  * wouldn't hammer the system with single-byte serial port
  3479.  * reads.  Also, the buffering makes char_avail() a lot
  3480.  * easier to implement.
  3481.  **********************************************************/
  3482. short
  3483. readock(struct Vars *v, short tenths)
  3484. {
  3485.   long      t;
  3486.  
  3487. /*
  3488.  * If there's data waiting in our buffer, return next byte
  3489.  */
  3490.   if (v->Modemcount)
  3491.     {
  3492.     gotdata:
  3493.       --v->Modemcount;
  3494.       return (short) (*v->Modemchar++);
  3495.     }
  3496. /*
  3497.  * Our buffer is empty; see if there's anything waiting in system buffer. *
  3498.  * If the caller is in a hurry, don't wait around, but if it can spare * a
  3499.  * half second, wait a bit and build up some input so we don't do as * many
  3500.  * sread() calls.
  3501.  */
  3502.   t = (tenths < 5) ? 0 : 500000;
  3503.   v->Modemcount = xpr_sread(v->Modembuf, (long) sizeof(v->Modembuf),
  3504.                                       t);
  3505.   if (v->Modemcount < 0)        /*
  3506.                                  * Carrier dropped or other fatal error;
  3507.                                  * abort
  3508.                                  */
  3509.     {
  3510.       v->Modemcount = 0;
  3511.       return RCDO;
  3512.     }
  3513.   else if (!v->Modemcount)      /*
  3514.                                  * Nothing in system buffer; try waiting
  3515.                                  */
  3516.     {
  3517.       t = tenths * 100000L - t;
  3518.       v->Modemcount = xpr_sread(v->Modembuf, 1L, t);
  3519.       if (v->Modemcount < 0)
  3520.         {
  3521.           v->Modemcount = 0;
  3522.           return RCDO;
  3523.         }
  3524.       else if (!v->Modemcount)  /*
  3525.                                  * Nothing received in time
  3526.                                  */
  3527.         return TIMEOUT;
  3528.     }
  3529.  
  3530. /*
  3531.  * Do the bookkeeping.
  3532.  */
  3533.   v->BytesReceived += v->Modemcount;
  3534.  
  3535. /*
  3536.  * Reset buffer pointer to start of data
  3537.  */
  3538.   v->Modemchar = v->Modembuf;
  3539.   goto gotdata;
  3540. }       /*
  3541.          * End of short readock()
  3542.          */
  3543.  
  3544. /**********************************************************
  3545.  *      char char_avail(struct Vars *v)
  3546.  *
  3547.  * Check if there's anything available to read from the
  3548.  * modem
  3549.  **********************************************************/
  3550. char
  3551. char_avail(struct Vars *v)
  3552. {
  3553.   if (v->Modemcount)
  3554.     return TRUE;
  3555.  
  3556. /*
  3557.  * No data in our buffer; check system's input buffer
  3558.  */
  3559.   v->Modemcount = xpr_sread(v->Modembuf, (long) sizeof(v->Modembuf), 0L);
  3560.   if (v->Modemcount < 1)        /*
  3561.                                  * Nothing in system buffer either
  3562.                                  */
  3563.     {
  3564.       v->Modemcount = 0;
  3565.       return FALSE;
  3566.     }
  3567.   else
  3568.     {
  3569.  /*
  3570.   * Do the bookkeeping.
  3571.   */
  3572.       v->BytesReceived += v->Modemcount;
  3573.  
  3574.  /*
  3575.   * System buffer had something waiting for us
  3576.   */
  3577.       v->Modemchar = v->Modembuf;
  3578.       return TRUE;
  3579.     }
  3580. }       /*
  3581.          * End of char char_avail()
  3582.          */
  3583.  
  3584. /**********************************************************
  3585.  *      void update_rate(struct Vars *v)
  3586.  *
  3587.  * Update the elapsed time, expected total time, and
  3588.  * effective data transfer rate values for status display
  3589.  **********************************************************/
  3590. void
  3591. update_rate(struct Vars *v)
  3592. {
  3593.   ULONG     elapsed,
  3594.             expect,
  3595.             throughput,
  3596.             time,
  3597.             oldrate = v->xpru.xpru_datarate;
  3598.   struct timeval Now;
  3599.  
  3600. /*
  3601.  * What time is it?
  3602.  */
  3603.   GetSysTime(&Now);
  3604.  
  3605. /*
  3606.  * Now calculate the time elapsed since the protocol started * transferring
  3607.  * the current file.
  3608.  */
  3609.   if (CmpTime(&Now, &v->Starttime) > 0)
  3610.     Now.tv_secs = Now.tv_micro = 0;
  3611.   else
  3612.     SubTime(&Now, &v->Starttime);
  3613.   elapsed = Now.tv_secs;
  3614.  
  3615. /*
  3616.  * Now take a look at the data that go through so far.
  3617.  */
  3618.   if (v->Receiving)
  3619.     throughput = v->BytesReceived;
  3620.   else
  3621.     throughput = v->BytesSent;
  3622.  
  3623. /*
  3624.  * Cut off the lowest 24 bits.
  3625.  */
  3626.   if (throughput > 0x00FFFFFF)
  3627.     throughput = 0xFFFFFF00;
  3628.   else
  3629.     throughput = throughput << 8;
  3630.  
  3631. /*
  3632.  * Now calculate the time.
  3633.  */
  3634.   if (elapsed > 0x00FFFFFF)
  3635.     time = 0xFFFFFF00 | (Now.tv_micro >> 12);
  3636.   else
  3637.     time = (elapsed << 8) | (Now.tv_micro >> 12);
  3638.  
  3639. /*
  3640.  * Finally, calculate the effective number of characters * transferred per
  3641.  * second.
  3642.  */
  3643.   if (time)
  3644.     {
  3645.       if (v->xpru.xpru_datarate = throughput / time)
  3646.         v->xpru.xpru_updatemask |= XPRU_DATARATE;
  3647.       else
  3648.         v->xpru.xpru_updatemask &= ~XPRU_DATARATE;
  3649.     }
  3650.   else
  3651.     {
  3652.       v->xpru.xpru_datarate = 0;
  3653.       v->xpru.xpru_updatemask &= ~XPRU_DATARATE;
  3654.     }
  3655.  
  3656. /*
  3657.  * Any changes?
  3658.  */
  3659.   if (v->xpru.xpru_datarate == oldrate)
  3660.     v->xpru.xpru_updatemask &= ~(XPRU_DATARATE | XPRU_EXPECTTIME);
  3661.  
  3662. /*
  3663.  * Compute expected total transfer time based on data rate so far
  3664.  */
  3665.   if (v->xpru.xpru_filesize <= 0 || !v->xpru.xpru_datarate)
  3666.     v->xpru.xpru_updatemask &= ~XPRU_EXPECTTIME;
  3667.   else
  3668.     {
  3669.       if ((expect = (v->xpru.xpru_filesize - v->Strtpos) / v->xpru.xpru_datarate) < elapsed)
  3670.         expect = elapsed;
  3671.  
  3672.       v->xpru.xpru_updatemask |= XPRU_EXPECTTIME;
  3673.     }
  3674.  
  3675. /*
  3676.  * Any data to display?
  3677.  */
  3678.   if (v->xpru.xpru_updatemask & XPRU_EXPECTTIME)
  3679.     {
  3680.       v->xpru.xpru_expecttime = (char *) v->Msgbuf;
  3681.  
  3682.       sprintf(v->xpru.xpru_expecttime, "%02ld:%02ld:%02ld", expect / (60 * 60), (expect / 60) % 60, expect % 60);
  3683.  
  3684.       v->xpru.xpru_elapsedtime = &v->xpru.xpru_expecttime[strlen(v->xpru.xpru_expecttime) + 1];
  3685.     }
  3686.   else
  3687.     v->xpru.xpru_elapsedtime = v->Msgbuf;
  3688.  
  3689.   sprintf(v->xpru.xpru_elapsedtime, "%02ld:%02ld:%02ld", elapsed / (60 * 60), (elapsed / 60) % 60, elapsed % 60);
  3690. }
  3691.  
  3692. /**********************************************************
  3693.  *      long bfopen(struct Vars *v, UBYTE *mode)
  3694.  *
  3695.  * Buffered file I/O fopen() interface routine
  3696.  **********************************************************/
  3697. FILE *
  3698. bfopen(struct Vars *v, UBYTE *mode)
  3699. {
  3700. /*
  3701.  * Initialize file-handling variables
  3702.  */
  3703.   v->Filebufpos = v->Filebuflen = v->Filebufcnt = 0;
  3704.   v->Fileflush = FALSE;
  3705.   v->Filebufptr = v->Filebuf;
  3706. /*
  3707.  * Open the file
  3708.  */
  3709.   return fopen (v->Filename, mode);
  3710. }
  3711.  
  3712. /**********************************************************
  3713.  *      void bfclose(struct Vars *v)
  3714.  *
  3715.  * Buffered file I/O fclose() interface routine
  3716.  **********************************************************/
  3717. void
  3718. bfclose(struct Vars *v)
  3719. {
  3720.   if (v->File)
  3721.     {
  3722.  /*
  3723.   * If bfwrite() left data in buffer, flush it out before closing
  3724.   */
  3725.       if (v->Fileflush)
  3726.         fwrite (v->Filebuf, 1L, v->Filebufcnt, v->File);
  3727.  
  3728.  /*
  3729.   * Close the file
  3730.   */
  3731.       fclose (v->File);
  3732.  
  3733.  /*
  3734.   * Let's see if we should muck with the file attributes.
  3735.   */
  3736.       if (v->SetAttributes && (v->FileAttributes & 2))
  3737.         {
  3738.           ULONG     Bits = 0,
  3739.                     Seconds;
  3740.  
  3741.             Seconds = 0;
  3742.  
  3743.      /*
  3744.       * Take care of the owner bits.
  3745.       */
  3746.           if (v->Bits & 0100)
  3747.             Bits |= FIBF_EXECUTE;
  3748.  
  3749.           if (v->Bits & 0200)
  3750.             Bits |= FIBF_WRITE | FIBF_DELETE;
  3751.  
  3752.           if (v->Bits & 0400)
  3753.             Bits |= FIBF_READ;
  3754.  
  3755.      /*
  3756.       * Now for the group bits.
  3757.       */
  3758.           if (!(v->Bits & 0010))
  3759.             Bits |= FIBF_GRP_EXECUTE;
  3760.  
  3761.           if (!(v->Bits & 0020))
  3762.             Bits |= FIBF_GRP_WRITE | FIBF_GRP_DELETE;
  3763.  
  3764.           if (!(v->Bits & 0040))
  3765.             Bits |= FIBF_GRP_READ;
  3766.  
  3767.      /*
  3768.       * Now for the other bits.
  3769.       */
  3770.           if (!(v->Bits & 0001))
  3771.             Bits |= FIBF_OTR_EXECUTE;
  3772.  
  3773.           if (!(v->Bits & 0002))
  3774.             Bits |= FIBF_OTR_WRITE | FIBF_OTR_DELETE;
  3775.  
  3776.           if (!(v->Bits & 0004))
  3777.             Bits |= FIBF_OTR_READ;
  3778.  
  3779.      /*
  3780.       * Try to change the attributes.
  3781.       */
  3782.           SetProtection(v->Filename, Bits);
  3783.  
  3784.      /*
  3785.       * Now for the modification date.
  3786.       */
  3787.           if (Seconds)
  3788.             {
  3789.               struct DateStamp __aligned Date;
  3790.  
  3791.               Date.ds_Days = Seconds / 86400;
  3792.               Date.ds_Minute = (Seconds % 86400) / 60;
  3793.               Date.ds_Tick = (Seconds % 60) * TICKS_PER_SECOND;
  3794.  
  3795.               SetFileDate(v->Filename, &Date);
  3796.             }
  3797.         }
  3798.  
  3799.       v->File = NULL;
  3800.     }
  3801. }       /*
  3802.          * End of void bfclose()
  3803.          */
  3804.  
  3805. /**********************************************************
  3806.  *      void bfseek(struct Vars *v, long pos)
  3807.  *
  3808.  * Buffered file I/O fseek() interface routine
  3809.  **********************************************************/
  3810. void
  3811. bfseek(struct Vars *v, long pos)
  3812. {
  3813.   long      offset;
  3814.  
  3815. /*
  3816.  * If new file position is within currently buffered section, reset pointers
  3817.  */
  3818.   if (pos >= v->Filebufpos && pos < v->Filebufpos + v->Filebuflen)
  3819.     {
  3820.       offset = pos - v->Filebufpos;
  3821.       v->Filebufptr = v->Filebuf + offset;
  3822.       v->Filebufcnt = v->Filebuflen - offset;
  3823.  /*
  3824.   * Otherwise, fseek() file & discard buffer contents to force new read
  3825.   */
  3826.     }
  3827.   else
  3828.     {
  3829.       fseek (v->File, pos, SEEK_SET);
  3830.       v->Filebuflen = v->Filebufcnt = 0;
  3831.       v->Filebufpos = pos;
  3832.     }
  3833. }       /*
  3834.          * End of void bfseek()
  3835.          */
  3836.  
  3837. /**********************************************************
  3838.  *      long bfread(struct Vars *v, UBYTE *buf, long length)
  3839.  *
  3840.  * Buffered file I/O fread() interface routine
  3841.  **********************************************************/
  3842. long
  3843. bfread(struct Vars *v, UBYTE *buf, long length)
  3844. {
  3845.   long      count,
  3846.             total = 0;
  3847.  
  3848. /*
  3849.  * Keep going until entire request completed
  3850.  */
  3851.   while (length > 0)
  3852.     {
  3853.  /*
  3854.   * Copy as much of the request as possible from the buffer
  3855.   */
  3856.       count = (length <= v->Filebufcnt) ? length : v->Filebufcnt;
  3857.       CopyMem(v->Filebufptr, buf, count);
  3858.       buf += count;
  3859.       total += count;
  3860.       length -= count;
  3861.       v->Filebufptr += count;
  3862.       v->Filebufcnt -= count;
  3863.  
  3864.  /*
  3865.   * If we've emptied the buffer, read next buffer's worth
  3866.   */
  3867.       if (!v->Filebufcnt)
  3868.         {
  3869.           v->Filebufpos += v->Filebuflen;
  3870.           v->Filebufptr = v->Filebuf;
  3871.           v->Filebufcnt = v->Filebuflen
  3872.             = fread (v->Filebuf, 1L, v->Filebufmax, v->File);
  3873.      /*
  3874.       * If we hit the EOF, return with however much we read so far
  3875.       */
  3876.           if (!v->Filebufcnt)
  3877.             break;
  3878.         }
  3879.     }
  3880.   return total;
  3881. }       /*
  3882.          * End of long bfread()
  3883.          */
  3884.  
  3885. /**********************************************************
  3886.  *      long bfwrite(struct Vars *v, UBYTE *buf, long length)
  3887.  *
  3888.  * Buffered file I/O fwrite() interface routine
  3889.  **********************************************************/
  3890. long
  3891. bfwrite(struct Vars *v, UBYTE *buf, long length)
  3892. {
  3893.   long      count,
  3894.             total = 0;
  3895.  
  3896. /*
  3897.  * Keep going until entire request completed
  3898.  */
  3899.   while (length > 0)
  3900.     {
  3901.  /*
  3902.   * Copy as much as will fit into the buffer
  3903.   */
  3904.       count = v->Filebufmax - v->Filebufcnt;
  3905.       if (length < count)
  3906.         count = length;
  3907.       CopyMem(buf, v->Filebufptr, count);
  3908.       buf += count;
  3909.       total += count;
  3910.       length -= count;
  3911.       v->Filebufptr += count;
  3912.       v->Filebufcnt += count;
  3913.       v->Fileflush = TRUE;
  3914.  
  3915.  /*
  3916.   * If we've filled the buffer, write it out
  3917.   */
  3918.       if (v->Filebufcnt == v->Filebufmax)
  3919.         {
  3920.           count = fwrite(v->Filebuf, 1L, v->Filebufcnt, v->File);
  3921.           if (count < v->Filebufcnt)
  3922.             return -1;
  3923.           v->Filebufptr = v->Filebuf;
  3924.           v->Filebufcnt = 0;
  3925.           v->Fileflush = FALSE;
  3926.         }
  3927.     }
  3928.   return total;
  3929. }       /*
  3930.          * End of long bfwrite()
  3931.          */
  3932.  
  3933. /**********************************************************
  3934.  *      void ioerr(struct XPR_IO *io, char *msg)
  3935.  *
  3936.  * Have the comm program display an error message for us,
  3937.  * using a temporary XPR_UPDATE structure; used to display
  3938.  * errors before Vars gets allocated
  3939.  **********************************************************/
  3940. void
  3941. ioerr(struct XPR_IO *io, char *msg)
  3942. {
  3943.   struct XPR_UPDATE xpru;
  3944.  
  3945.       xpru.xpru_updatemask = XPRU_ERRORMSG;
  3946.       xpru.xpru_errormsg = msg;
  3947.       display_update(&xpru);
  3948. }       /** End of void ioerr() */
  3949.  
  3950. /**********************************************************
  3951.  *      void upderr(struct Vars *v, char *msg)
  3952.  *
  3953.  * Have the comm program display an error message for us, using the
  3954.  * normal XPR_IO structure allocated in Vars
  3955.  **********************************************************/
  3956. void
  3957. upderr(struct Vars *v, char *msg)
  3958. {
  3959.   v->xpru.xpru_updatemask = XPRU_ERRORMSG;
  3960.   v->xpru.xpru_errormsg = (STRPTR) msg;
  3961.   if ((STRPTR) msg == v->Msgbuf)        /*
  3962.                                          * Ensure message length < 50
  3963.                                          */
  3964.     msg[48] = '\0';
  3965.   display_update (&v->xpru);
  3966. }
  3967.  
  3968. /**********************************************************
  3969.  *      void updmsg(struct Vars *v,char *msg)
  3970.  *
  3971.  * Have the comm program display a normal message for us
  3972.  **********************************************************/
  3973. void
  3974. updmsg(struct Vars *v, char *msg)
  3975. {
  3976.   v->xpru.xpru_updatemask = XPRU_MSG;
  3977.   v->xpru.xpru_msg = (STRPTR) msg;
  3978.   if ((STRPTR) msg == v->Msgbuf)        /*
  3979.                                          * Ensure message length < 50
  3980.                                          */
  3981.     msg[48] = '\0';
  3982.   display_update(&v->xpru);
  3983. }
  3984.  
  3985. /**********************************************************
  3986.  *      long getfree(void)
  3987.  *
  3988.  * Figure out how many bytes are free on the drive we're uploading to.
  3989.  * Stubbed out for now; not supported by XPR spec.
  3990.  **********************************************************/
  3991. long
  3992. getfree(struct Vars *v)
  3993. {
  3994.   LONG      Space = 0x7FFFFFFF;   /*
  3995.                                    * = Unknown
  3996.                                    */
  3997.   return (Space);
  3998.  
  3999. }
  4000.  
  4001. /**********************************************************
  4002.  *      char exist(struct Vars *v)
  4003.  *
  4004.  * Check whether file already exists; used to detect
  4005.  * potential overwrites
  4006.  **********************************************************/
  4007. char
  4008. exist(struct Vars *v)
  4009. {
  4010.   FILE *alock;
  4011.   alock = fopen(v->Filename,"R");
  4012.   if( alock )
  4013.     {
  4014.     fclose(alock);
  4015.     };
  4016.   return (char)(alock != NULL);
  4017. }
  4018.